From d9f60a43c7699f075e90af1953ad3025a5921553 Mon Sep 17 00:00:00 2001 From: Kosta Date: Thu, 8 Oct 2026 20:07:05 +0300 Subject: [PATCH 1/5] feat: read both API response shapes; never send an empty webhook_url on verify Every model, the webhook parser, the error mapping and the CLI read the API's newer response shape as well as the original one. The newer field names are attributes (ExtractedClaims.claims, AssessClaim.status/failure/ more_claims, TaskStatus.failure, completed_at, claim, FailureBlock.code, the *_limit_exceeded flags, webhook event_id), and every older attribute keeps its original meaning, computed from whichever shape arrives. model_dump() returns the shape the server sent. verify and verify_batch leave webhook_url out instead of sending "" (both meant the key's default); review and citecheck bodies are unchanged. The /me/usage deprecations no longer name a removal date. Parity tests freeze what the previous release produced from each original-shape response (models, CLI text and JSON, wait outcomes, errors, webhooks, request bodies) and hold both shapes to it. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 76 ++ README.md | 79 +- openapi.json | 8 +- src/lenz_io/__init__.py | 12 +- src/lenz_io/cli/render.py | 30 +- src/lenz_io/cli/verify.py | 4 +- src/lenz_io/client.py | 62 +- src/lenz_io/errors.py | 37 +- src/lenz_io/models.py | 805 +++++++++++++++--- src/lenz_io/webhooks.py | 239 +++--- .../canonical/account__library_empty.json | 14 + ...dified_at_crosses_midnight_by_minutes.json | 30 + ...item_modified_at_same_day_hours_apart.json | 30 + .../canonical/account__library_items.json | 60 ++ .../canonical/account__library_no_match.json | 14 + .../account__library_page_past_end.json | 14 + ...ccount__library_paginated_second_page.json | 45 + .../account__me_usage_extra_credits.json | 40 + .../account__me_usage_extra_only.json | 40 + .../account__me_usage_extract_calls.json | 40 + .../canonical/account__me_usage_free.json | 40 + .../account__me_usage_free_partly_spent.json | 40 + .../canonical/account__me_usage_plus.json | 40 + .../canonical/account__me_usage_pro.json | 40 + .../account__me_usage_pro_extra.json | 40 + .../account__me_usage_stale_quota_row.json | 40 + .../parity/canonical/assess__401_no_key.json | 12 + .../canonical/assess__402_no_credits.json | 19 + .../canonical/assess__422_blank_item.json | 23 + .../canonical/assess__422_blank_text.json | 22 + .../canonical/assess__422_input_conflict.json | 22 + .../canonical/assess__422_item_too_long.json | 23 + .../canonical/assess__422_no_input_field.json | 23 + .../canonical/assess__422_too_many_items.json | 22 + .../assess__422_wrong_type_claim.json | 23 + .../assess__422_wrong_type_claims.json | 23 + .../canonical/assess__502_framing_failed.json | 12 + .../canonical/assess__503_capacity.json | 15 + ...ss__503_list_all_upstream_unavailable.json | 15 + .../assess__503_upstream_unavailable.json | 15 + .../canonical/assess__deep_tier_hit.json | 28 + .../assess__idempotency_body_mismatch.json | 12 + .../canonical/assess__idempotency_first.json | 28 + .../canonical/assess__idempotency_replay.json | 28 + .../assess__list_all_error_rows.json | 55 ++ .../canonical/assess__list_compound_item.json | 44 + .../canonical/assess__list_mixed_rows.json | 88 ++ .../parity/canonical/assess__memo_hit.json | 28 + .../canonical/assess__replay_later_200.json | 28 + .../canonical/assess__single_no_claim.json | 21 + .../canonical/assess__single_one_claim.json | 28 + ...ss__single_text_over_wave_more_claims.json | 278 ++++++ .../assess__single_text_several_claims.json | 54 ++ .../canonical/assess__suggest_rewrite.json | 41 + .../canonical/citecheck__402_no_credits.json | 18 + .../canonical/citecheck__422_empty_body.json | 25 + .../canonical/citecheck__422_invalid_doi.json | 25 + .../citecheck__422_max_citations_over_20.json | 26 + ...techeck__422_max_citations_with_pairs.json | 25 + .../citecheck__422_pair_bad_url_scheme.json | 28 + .../citecheck__422_pair_no_source.json | 27 + .../citecheck__422_pair_url_and_doi.json | 27 + .../canonical/citecheck__422_pairs_empty.json | 26 + .../citecheck__422_pairs_over_20.json | 26 + ...citecheck__422_quote_not_in_statement.json | 24 + .../citecheck__422_text_and_pairs.json | 25 + .../citecheck__422_unknown_field.json | 25 + .../canonical/citecheck__422_url_input.json | 22 + .../citecheck__429_citecheck_in_flight.json | 14 + .../canonical/citecheck__503_capacity.json | 15 + .../citecheck__503_citations_unavailable.json | 15 + .../citecheck__get_404_not_found.json | 12 + .../citecheck__get_404_review_id.json | 12 + .../canonical/citecheck__get_410_purged.json | 13 + .../canonical/citecheck__get_checking.json | 103 +++ .../citecheck__get_completed_clean.json | 111 +++ .../citecheck__get_completed_doi_pair.json | 76 ++ .../citecheck__get_completed_incomplete.json | 129 +++ ...citecheck__get_completed_issues_found.json | 141 +++ ...check__get_completed_partly_supported.json | 111 +++ .../citecheck__get_completed_unchecked.json | 111 +++ .../citecheck__get_failed_no_citations.json | 43 + ...heck__get_failed_upstream_unavailable.json | 153 ++++ .../canonical/citecheck__get_queued.json | 72 ++ ...heck__get_text_limit_exactly_at_limit.json | 119 +++ .../citecheck__get_text_limit_reached.json | 93 ++ ...echeck__idempotency_body_mismatch_422.json | 12 + .../citecheck__idempotency_conflict_409.json | 13 + .../citecheck__idempotent_replay_202.json | 14 + .../canonical/citecheck__receipt_202.json | 14 + ...echeck__receipt_202_empty_webhook_url.json | 14 + .../canonical/errors__ask_bad_language.json | 22 + .../canonical/errors__ask_empty_message.json | 22 + .../parity/canonical/errors__ask_failed.json | 12 + .../errors__ask_idempotency_key_reused.json | 12 + .../errors__ask_message_too_long.json | 22 + .../canonical/errors__ask_not_completed.json | 12 + .../errors__ask_reset_not_found.json | 12 + .../canonical/errors__ask_send_not_found.json | 12 + .../canonical/errors__auth_bad_key.json | 12 + .../canonical/errors__auth_basic_scheme.json | 12 + .../errors__auth_insufficient_scope.json | 14 + .../errors__auth_missing_bearer.json | 12 + .../errors__auth_missing_bearer_post.json | 12 + ...rrors__auth_private_claim_ask_history.json | 12 + .../errors__auth_private_claim_ask_send.json | 12 + .../errors__auth_unrecognised_prefix.json | 12 + ...rrors__http_error_library_bad_curated.json | 22 + ...rrors__http_error_library_bad_verdict.json | 22 + .../canonical/errors__not_found_ask.json | 12 + .../canonical/errors__not_found_route.json | 12 + .../errors__not_found_verification.json | 12 + .../errors__not_found_verify_status.json | 12 + .../errors__payment_required_ask.json | 19 + .../errors__payment_required_assess.json | 19 + .../errors__payment_required_verify.json | 19 + ...__payment_required_verify_batch_short.json | 20 + .../errors__rate_limited_extract.json | 17 + .../errors__service_unavailable_ask.json | 15 + .../errors__service_unavailable_capacity.json | 15 + .../errors__validation_malformed_json.json | 12 + ...errors__validation_missing_field_hint.json | 29 + ...errors__validation_unknown_field_only.json | 28 + ...__validation_unknown_field_wrong_type.json | 27 + .../errors__validation_wrong_type.json | 23 + .../parity/canonical/extract__401_no_key.json | 12 + .../canonical/extract__422_blank_text.json | 22 + .../extract__422_focus_too_long.json | 22 + .../canonical/extract__422_missing_text.json | 23 + .../canonical/extract__429_daily_limit.json | 17 + .../extract__502_extraction_failed.json | 12 + .../extract__503_upstream_unavailable.json | 15 + .../canonical/extract__focus_ready.json | 30 + ...xtract__idempotency_body_mismatch_422.json | 12 + .../extract__idempotency_replay.json | 34 + .../extract__locate_all_dropped.json | 25 + .../canonical/extract__locate_failed.json | 34 + .../extract__locate_leading_whitespace.json | 36 + .../extract__locate_some_dropped.json | 46 + .../canonical/extract__locate_true.json | 46 + .../extract__no_match_with_focus.json | 16 + .../canonical/extract__not_a_claim.json | 16 + .../extract__not_a_claim_beside_claims.json | 30 + .../canonical/extract__ready_one_claim.json | 30 + .../extract__ready_several_claims.json | 34 + .../canonical/extract__replay_later_200.json | 31 + .../extract__url_fetch_502_unreadable.json | 12 + .../extract__url_fetch_503_upstream.json | 15 + .../canonical/extract__url_input_located.json | 36 + .../canonical/review__401_no_credentials.json | 12 + .../canonical/review__402_no_credits.json | 19 + .../review__402_no_credits_exhausted.json | 19 + .../canonical/review__422_blank_text.json | 22 + .../review__422_citations_options_object.json | 23 + .../canonical/review__422_depth_unknown.json | 27 + .../review__422_invalid_confidence_band.json | 27 + .../review__422_invalid_verdict_label.json | 28 + .../review__422_max_assessments_negative.json | 27 + .../review__422_max_citations_negative.json | 27 + .../review__422_max_citations_too_big.json | 27 + ...review__422_max_verifications_too_big.json | 27 + .../canonical/review__422_text_missing.json | 23 + .../review__422_text_wrong_type.json | 23 + .../review__422_unknown_escalate_field.json | 24 + .../review__422_unknown_top_level_field.json | 23 + .../review__422_unsupported_language.json | 22 + .../review__422_visibility_public.json | 26 + .../review__429_extract_daily_limit.json | 17 + .../review__429_review_in_flight.json | 14 + .../canonical/review__503_capacity.json | 15 + .../review__503_citations_capacity.json | 15 + .../review__get_403_insufficient_scope.json | 14 + .../canonical/review__get_404_not_found.json | 12 + .../review__get_404_other_account.json | 12 + .../canonical/review__get_410_purged.json | 13 + .../review__get_422_unknown_view.json | 22 + .../canonical/review__get_assessing.json | 107 +++ ...view__get_assessment_rows_full_fields.json | 169 ++++ .../review__get_citations_clean.json | 182 ++++ ...w__get_citations_failed_and_unchecked.json | 200 +++++ .../review__get_citations_issue_full.json | 204 +++++ ...view__get_citations_issue_issues_view.json | 94 ++ ..._get_citations_limit_exactly_at_limit.json | 182 ++++ .../review__get_citations_limit_reached.json | 156 ++++ ..._get_citations_no_claim_but_citations.json | 153 ++++ ...w__get_citations_no_claim_no_citation.json | 70 ++ .../review__get_citations_not_asked.json | 99 +++ .../canonical/review__get_citations_only.json | 160 ++++ ...eview__get_citations_partly_supported.json | 182 ++++ .../review__get_citations_running.json | 166 ++++ ...w__get_citations_skipped_switched_off.json | 99 +++ ...view__get_citations_skipped_url_input.json | 70 ++ .../review__get_claim_limit_not_reached.json | 127 +++ ...review__get_claim_limit_reached_exact.json | 127 +++ .../review__get_completed_assess_only.json | 153 ++++ .../review__get_completed_clean.json | 127 +++ ...ew__get_completed_issues_all_verified.json | 256 ++++++ .../review__get_completed_issues_full.json | 309 +++++++ ...iew__get_completed_issues_view_issues.json | 136 +++ .../review__get_completed_positions.json | 139 +++ ...review__get_completed_recovered_claim.json | 99 +++ ...ew__get_completed_with_untraced_claim.json | 139 +++ .../review__get_during_quick_check.json | 87 ++ ...w__get_failed_every_assessment_failed.json | 159 ++++ .../review__get_failed_no_claim.json | 70 ++ .../review__get_failed_no_claim_untraced.json | 70 ++ .../canonical/review__get_more_claims.json | 152 ++++ ...dified_at_crosses_midnight_by_minutes.json | 150 ++++ ...tion_modified_at_same_day_hours_apart.json | 150 ++++ .../review__get_policy_resolved.json | 97 +++ .../parity/canonical/review__get_queued.json | 63 ++ .../review__get_suggested_edits.json | 266 ++++++ ...view__get_suggested_edits_issues_view.json | 129 +++ .../canonical/review__get_url_review.json | 105 +++ .../canonical/review__get_verifying.json | 176 ++++ ...review__idempotency_body_mismatch_422.json | 12 + .../review__idempotency_conflict_409.json | 13 + ...mpotency_conflict_409_existing_review.json | 13 + .../review__idempotent_replay_202.json | 14 + .../parity/canonical/review__receipt_202.json | 14 + ...review__receipt_202_empty_webhook_url.json | 14 + .../review__receipt_202_webhook_url.json | 14 + .../canonical/review__replay_later_202.json | 14 + .../parity/canonical/verify__batch_202.json | 21 + .../canonical/verify__batch_capacity_503.json | 15 + .../canonical/verify__batch_empty_422.json | 22 + ...erify__batch_idempotency_conflict_409.json | 13 + .../verify__batch_item_missing_claim_422.json | 25 + .../verify__batch_no_credits_402.json | 20 + .../canonical/verify__batch_partial_202.json | 18 + .../canonical/verify__batch_too_many_422.json | 22 + .../canonical/verify__blank_claim_422.json | 22 + .../canonical/verify__capacity_503.json | 15 + ...verify__idempotency_body_mismatch_422.json | 12 + .../verify__idempotency_conflict_409.json | 13 + .../verify__idempotency_key_replay.json | 12 + .../canonical/verify__implicit_dedup_200.json | 12 + .../verify__implicit_repeat_replay.json | 12 + .../canonical/verify__invalid_depth_422.json | 26 + .../verify__invalid_language_422.json | 22 + .../parity/canonical/verify__list_200.json | 45 + ...dified_at_crosses_midnight_by_minutes.json | 30 + ..._200_modified_at_same_day_hours_apart.json | 30 + .../canonical/verify__list_clamped_200.json | 14 + .../canonical/verify__list_empty_200.json | 14 + .../canonical/verify__list_page2_200.json | 30 + .../canonical/verify__misnamed_field_422.json | 28 + .../canonical/verify__missing_claim_422.json | 23 + .../canonical/verify__no_credits_402.json | 19 + .../canonical/verify__replay_later_202.json | 13 + .../parity/canonical/verify__select_202.json | 21 + .../canonical/verify__select_empty_422.json | 22 + .../verify__select_invalid_selection_422.json | 22 + ...rify__select_no_selection_pending_409.json | 12 + .../verify__select_too_many_422.json | 22 + .../verify__select_unknown_task_404.json | 12 + ...erify__status_cancelled_after_a_while.json | 20 + .../canonical/verify__status_completed.json | 99 +++ ...erify__status_completed_after_a_while.json | 99 +++ ...dified_at_crosses_midnight_by_minutes.json | 99 +++ ...hile_modified_at_same_day_hours_apart.json | 99 +++ ...dified_at_crosses_midnight_by_minutes.json | 99 +++ ...eted_modified_at_same_day_hours_apart.json | 99 +++ .../canonical/verify__status_failed.json | 20 + .../verify__status_failed_after_a_while.json | 20 + ...__status_failed_after_a_while_framing.json | 20 + .../verify__status_failed_retryable.json | 20 + .../canonical/verify__status_needs_input.json | 24 + .../canonical/verify__status_not_a_claim.json | 20 + ...ify__status_not_a_claim_after_a_while.json | 20 + .../verify__status_not_yours_404.json | 12 + .../verify__status_older_run_completed.json | 99 +++ ...rify__status_older_run_failed_crashed.json | 20 + ...lder_run_failed_insufficient_evidence.json | 20 + .../verify__status_older_run_in_progress.json | 19 + .../canonical/verify__status_processing.json | 19 + ...rify__status_processing_after_a_while.json | 19 + .../canonical/verify__status_task_stuck.json | 20 + .../canonical/verify__status_unknown_404.json | 12 + .../parity/canonical/verify__submit_202.json | 12 + .../canonical/verify__submit_202_options.json | 12 + .../verify__submit_202_text_alias.json | 12 + .../verify__unauthenticated_401.json | 12 + .../canonical/verify__verification_200.json | 95 +++ .../verify__verification_200_covered.json | 93 ++ ...dified_at_crosses_midnight_by_minutes.json | 95 +++ ...fy__verification_200_modified_at_null.json | 95 +++ ..._200_modified_at_same_day_hours_apart.json | 95 +++ ...ify__verification_200_modified_at_set.json | 95 +++ ...ation_200_result_json_conclusion_only.json | 56 ++ ...y__verification_200_result_json_empty.json | 56 ++ ...ion_200_result_json_old_shape_strings.json | 72 ++ .../canonical/verify__verification_404.json | 12 + .../verify__verification_by_task_id_200.json | 95 +++ .../verify__verification_failed_409.json | 23 + ..._failed_409_not_a_claim_after_a_while.json | 23 + .../verify__verification_not_ready_409.json | 15 + .../verify__verification_not_yours_404.json | 12 + ...verify__verification_public_anonymous.json | 83 ++ ...__verification_public_of_another_user.json | 95 +++ ...verify__verification_unknown_task_404.json | 13 + ...rification_zero_retention_expired_410.json | 13 + ...y__verification_zero_retention_served.json | 95 +++ .../webhook__certificate_timestamped.json | 25 + ..._certificate_timestamped_review_child.json | 26 + .../webhook__citecheck_completed.json | 133 +++ .../canonical/webhook__citecheck_failed.json | 46 + .../canonical/webhook__review_completed.json | 155 ++++ ...ook__review_completed_key_default_url.json | 104 +++ ...k__review_completed_oversized_rebuilt.json | 10 + .../canonical/webhook__review_failed.json | 72 ++ .../webhook__verification_completed.json | 109 +++ ...hook__verification_completed_in_batch.json | 109 +++ ...dified_at_crosses_midnight_by_minutes.json | 109 +++ ...eted_modified_at_same_day_hours_apart.json | 109 +++ ...fication_failed_insufficient_evidence.json | 26 + ...hook__verification_failed_not_a_claim.json | 26 + ...ification_failed_upstream_unavailable.json | 26 + ..._verification_needs_input_multi_claim.json | 30 + .../expected/account__library_empty.json | 9 + ...dified_at_crosses_midnight_by_minutes.json | 25 + ...item_modified_at_same_day_hours_apart.json | 25 + .../expected/account__library_items.json | 55 ++ .../expected/account__library_no_match.json | 9 + .../account__library_page_past_end.json | 9 + ...ccount__library_paginated_second_page.json | 40 + .../account__me_usage_extra_credits.json | 62 ++ .../account__me_usage_extra_only.json | 62 ++ .../account__me_usage_extract_calls.json | 62 ++ .../expected/account__me_usage_free.json | 62 ++ .../account__me_usage_free_partly_spent.json | 62 ++ .../expected/account__me_usage_plus.json | 62 ++ .../expected/account__me_usage_pro.json | 62 ++ .../expected/account__me_usage_pro_extra.json | 62 ++ .../account__me_usage_stale_quota_row.json | 62 ++ .../parity/expected/assess__401_no_key.json | 21 + .../expected/assess__402_no_credits.json | 28 + .../expected/assess__422_blank_item.json | 22 + .../expected/assess__422_blank_text.json | 22 + .../expected/assess__422_input_conflict.json | 22 + .../expected/assess__422_item_too_long.json | 22 + .../expected/assess__422_no_input_field.json | 32 + .../expected/assess__422_too_many_items.json | 22 + .../assess__422_wrong_type_claim.json | 32 + .../assess__422_wrong_type_claims.json | 32 + .../expected/assess__502_framing_failed.json | 22 + .../parity/expected/assess__503_capacity.json | 22 + ...ss__503_list_all_upstream_unavailable.json | 22 + .../assess__503_upstream_unavailable.json | 22 + .../expected/assess__deep_tier_hit.json | 26 + .../assess__idempotency_body_mismatch.json | 22 + .../expected/assess__idempotency_first.json | 26 + .../expected/assess__idempotency_replay.json | 26 + .../expected/assess__list_all_error_rows.json | 40 + .../expected/assess__list_compound_item.json | 43 + .../expected/assess__list_mixed_rows.json | 68 ++ .../parity/expected/assess__memo_hit.json | 26 + .../expected/assess__replay_later_200.json | 26 + .../expected/assess__single_no_claim.json | 11 + .../expected/assess__single_one_claim.json | 26 + ...ss__single_text_over_wave_more_claims.json | 295 +++++++ .../assess__single_text_several_claims.json | 54 ++ .../expected/assess__suggest_rewrite.json | 40 + .../expected/citecheck__402_no_credits.json | 28 + .../expected/citecheck__422_empty_body.json | 30 + .../expected/citecheck__422_invalid_doi.json | 33 + .../citecheck__422_max_citations_over_20.json | 31 + ...techeck__422_max_citations_with_pairs.json | 30 + .../citecheck__422_pair_bad_url_scheme.json | 33 + .../citecheck__422_pair_no_source.json | 32 + .../citecheck__422_pair_url_and_doi.json | 32 + .../expected/citecheck__422_pairs_empty.json | 31 + .../citecheck__422_pairs_over_20.json | 31 + ...citecheck__422_quote_not_in_statement.json | 32 + .../citecheck__422_text_and_pairs.json | 30 + .../citecheck__422_unknown_field.json | 33 + .../expected/citecheck__422_url_input.json | 30 + .../citecheck__429_citecheck_in_flight.json | 25 + .../expected/citecheck__503_capacity.json | 22 + .../citecheck__503_citations_unavailable.json | 22 + .../citecheck__get_404_not_found.json | 21 + .../citecheck__get_404_review_id.json | 21 + .../expected/citecheck__get_410_purged.json | 22 + .../expected/citecheck__get_checking.json | 100 +++ .../citecheck__get_completed_clean.json | 108 +++ .../citecheck__get_completed_doi_pair.json | 73 ++ .../citecheck__get_completed_incomplete.json | 124 +++ ...citecheck__get_completed_issues_found.json | 138 +++ ...check__get_completed_partly_supported.json | 108 +++ .../citecheck__get_completed_unchecked.json | 108 +++ .../citecheck__get_failed_no_citations.json | 39 + ...heck__get_failed_upstream_unavailable.json | 145 ++++ .../expected/citecheck__get_queued.json | 69 ++ ...heck__get_text_limit_exactly_at_limit.json | 116 +++ .../citecheck__get_text_limit_reached.json | 90 ++ ...echeck__idempotency_body_mismatch_422.json | 29 + .../citecheck__idempotency_conflict_409.json | 21 + .../citecheck__idempotent_replay_202.json | 7 + .../expected/citecheck__receipt_202.json | 7 + ...echeck__receipt_202_empty_webhook_url.json | 7 + .../expected/errors__ask_bad_language.json | 22 + .../expected/errors__ask_empty_message.json | 22 + .../parity/expected/errors__ask_failed.json | 22 + .../errors__ask_idempotency_key_reused.json | 22 + .../errors__ask_message_too_long.json | 22 + .../expected/errors__ask_not_completed.json | 21 + .../expected/errors__ask_reset_not_found.json | 21 + .../expected/errors__ask_send_not_found.json | 21 + .../parity/expected/errors__auth_bad_key.json | 21 + .../expected/errors__auth_basic_scheme.json | 21 + .../errors__auth_insufficient_scope.json | 21 + .../expected/errors__auth_missing_bearer.json | 21 + .../errors__auth_missing_bearer_post.json | 21 + ...rrors__auth_private_claim_ask_history.json | 21 + .../errors__auth_private_claim_ask_send.json | 21 + .../errors__auth_unrecognised_prefix.json | 21 + ...rrors__http_error_library_bad_curated.json | 22 + ...rrors__http_error_library_bad_verdict.json | 22 + .../expected/errors__not_found_ask.json | 21 + .../expected/errors__not_found_route.json | 21 + .../errors__not_found_verification.json | 21 + .../errors__not_found_verify_status.json | 21 + .../errors__payment_required_ask.json | 28 + .../errors__payment_required_assess.json | 28 + .../errors__payment_required_verify.json | 28 + ...__payment_required_verify_batch_short.json | 28 + .../errors__rate_limited_extract.json | 25 + .../errors__service_unavailable_ask.json | 22 + .../errors__service_unavailable_capacity.json | 22 + .../errors__validation_malformed_json.json | 21 + ...errors__validation_missing_field_hint.json | 32 + ...errors__validation_unknown_field_only.json | 32 + ...__validation_unknown_field_wrong_type.json | 32 + .../errors__validation_wrong_type.json | 32 + .../parity/expected/extract__401_no_key.json | 21 + .../expected/extract__422_blank_text.json | 22 + .../expected/extract__422_focus_too_long.json | 22 + .../expected/extract__422_missing_text.json | 32 + .../expected/extract__429_daily_limit.json | 25 + .../extract__502_extraction_failed.json | 22 + .../extract__503_upstream_unavailable.json | 22 + .../parity/expected/extract__focus_ready.json | 24 + ...xtract__idempotency_body_mismatch_422.json | 22 + .../expected/extract__idempotency_replay.json | 27 + .../expected/extract__locate_all_dropped.json | 24 + .../expected/extract__locate_failed.json | 27 + .../extract__locate_leading_whitespace.json | 35 + .../extract__locate_some_dropped.json | 48 ++ .../parity/expected/extract__locate_true.json | 48 ++ .../extract__no_match_with_focus.json | 15 + .../parity/expected/extract__not_a_claim.json | 15 + .../extract__not_a_claim_beside_claims.json | 24 + .../expected/extract__ready_one_claim.json | 24 + .../extract__ready_several_claims.json | 27 + .../expected/extract__replay_later_200.json | 27 + .../extract__url_fetch_502_unreadable.json | 22 + .../extract__url_fetch_503_upstream.json | 22 + .../expected/extract__url_input_located.json | 35 + .../expected/review__401_no_credentials.json | 21 + .../expected/review__402_no_credits.json | 28 + .../review__402_no_credits_exhausted.json | 28 + .../expected/review__422_blank_text.json | 30 + .../review__422_citations_options_object.json | 31 + .../expected/review__422_depth_unknown.json | 32 + .../review__422_invalid_confidence_band.json | 32 + .../review__422_invalid_verdict_label.json | 32 + .../review__422_max_assessments_negative.json | 32 + .../review__422_max_citations_negative.json | 32 + .../review__422_max_citations_too_big.json | 32 + ...review__422_max_verifications_too_big.json | 32 + .../expected/review__422_text_missing.json | 31 + .../expected/review__422_text_wrong_type.json | 31 + .../review__422_unknown_escalate_field.json | 32 + .../review__422_unknown_top_level_field.json | 31 + .../review__422_unsupported_language.json | 30 + .../review__422_visibility_public.json | 31 + .../review__429_extract_daily_limit.json | 25 + .../review__429_review_in_flight.json | 25 + .../parity/expected/review__503_capacity.json | 22 + .../review__503_citations_capacity.json | 22 + .../review__get_403_insufficient_scope.json | 21 + .../expected/review__get_404_not_found.json | 21 + .../review__get_404_other_account.json | 21 + .../expected/review__get_410_purged.json | 22 + .../review__get_422_unknown_view.json | 30 + .../expected/review__get_assessing.json | 108 +++ ...view__get_assessment_rows_full_fields.json | 168 ++++ .../expected/review__get_citations_clean.json | 181 ++++ ...w__get_citations_failed_and_unchecked.json | 197 +++++ .../review__get_citations_issue_full.json | 203 +++++ ...view__get_citations_issue_issues_view.json | 93 ++ ..._get_citations_limit_exactly_at_limit.json | 181 ++++ .../review__get_citations_limit_reached.json | 155 ++++ ..._get_citations_no_claim_but_citations.json | 150 ++++ ...w__get_citations_no_claim_no_citation.json | 66 ++ .../review__get_citations_not_asked.json | 98 +++ .../expected/review__get_citations_only.json | 157 ++++ ...eview__get_citations_partly_supported.json | 181 ++++ .../review__get_citations_running.json | 165 ++++ ...w__get_citations_skipped_switched_off.json | 98 +++ ...view__get_citations_skipped_url_input.json | 66 ++ .../review__get_claim_limit_not_reached.json | 128 +++ ...review__get_claim_limit_reached_exact.json | 128 +++ .../review__get_completed_assess_only.json | 154 ++++ .../expected/review__get_completed_clean.json | 128 +++ ...ew__get_completed_issues_all_verified.json | 259 ++++++ .../review__get_completed_issues_full.json | 310 +++++++ ...iew__get_completed_issues_view_issues.json | 133 +++ .../review__get_completed_positions.json | 140 +++ ...review__get_completed_recovered_claim.json | 98 +++ ...ew__get_completed_with_untraced_claim.json | 140 +++ .../review__get_during_quick_check.json | 86 ++ ...w__get_failed_every_assessment_failed.json | 155 ++++ .../expected/review__get_failed_no_claim.json | 66 ++ .../review__get_failed_no_claim_untraced.json | 66 ++ .../expected/review__get_more_claims.json | 153 ++++ ...dified_at_crosses_midnight_by_minutes.json | 149 ++++ ...tion_modified_at_same_day_hours_apart.json | 149 ++++ .../expected/review__get_policy_resolved.json | 96 +++ .../parity/expected/review__get_queued.json | 60 ++ .../expected/review__get_suggested_edits.json | 267 ++++++ ...view__get_suggested_edits_issues_view.json | 128 +++ .../expected/review__get_url_review.json | 104 +++ .../expected/review__get_verifying.json | 177 ++++ ...review__idempotency_body_mismatch_422.json | 29 + .../review__idempotency_conflict_409.json | 21 + ...mpotency_conflict_409_existing_review.json | 21 + .../review__idempotent_replay_202.json | 7 + .../parity/expected/review__receipt_202.json | 7 + ...review__receipt_202_empty_webhook_url.json | 7 + .../review__receipt_202_webhook_url.json | 7 + .../expected/review__replay_later_202.json | 7 + .../parity/expected/verify__batch_202.json | 16 + .../expected/verify__batch_capacity_503.json | 22 + .../expected/verify__batch_empty_422.json | 22 + ...erify__batch_idempotency_conflict_409.json | 21 + .../verify__batch_item_missing_claim_422.json | 34 + .../verify__batch_no_credits_402.json | 28 + .../expected/verify__batch_partial_202.json | 13 + .../expected/verify__batch_too_many_422.json | 22 + .../expected/verify__blank_claim_422.json | 22 + .../parity/expected/verify__capacity_503.json | 22 + ...verify__idempotency_body_mismatch_422.json | 22 + .../verify__idempotency_conflict_409.json | 21 + .../verify__idempotency_key_replay.json | 9 + .../expected/verify__implicit_dedup_200.json | 8 + .../verify__implicit_repeat_replay.json | 9 + .../expected/verify__invalid_depth_422.json | 35 + .../verify__invalid_language_422.json | 22 + .../parity/expected/verify__list_200.json | 40 + ...dified_at_crosses_midnight_by_minutes.json | 25 + ..._200_modified_at_same_day_hours_apart.json | 25 + .../expected/verify__list_clamped_200.json | 9 + .../expected/verify__list_empty_200.json | 9 + .../expected/verify__list_page2_200.json | 25 + .../expected/verify__misnamed_field_422.json | 32 + .../expected/verify__missing_claim_422.json | 32 + .../expected/verify__no_credits_402.json | 28 + .../expected/verify__replay_later_202.json | 9 + .../parity/expected/verify__select_202.json | 16 + .../expected/verify__select_empty_422.json | 22 + .../verify__select_invalid_selection_422.json | 22 + ...rify__select_no_selection_pending_409.json | 21 + .../expected/verify__select_too_many_422.json | 22 + .../verify__select_unknown_task_404.json | 21 + ...erify__status_cancelled_after_a_while.json | 51 ++ .../expected/verify__status_completed.json | 203 +++++ ...erify__status_completed_after_a_while.json | 203 +++++ ...dified_at_crosses_midnight_by_minutes.json | 203 +++++ ...hile_modified_at_same_day_hours_apart.json | 203 +++++ ...dified_at_crosses_midnight_by_minutes.json | 203 +++++ ...eted_modified_at_same_day_hours_apart.json | 203 +++++ .../expected/verify__status_failed.json | 51 ++ .../verify__status_failed_after_a_while.json | 51 ++ ...__status_failed_after_a_while_framing.json | 51 ++ .../verify__status_failed_retryable.json | 51 ++ .../expected/verify__status_needs_input.json | 90 ++ .../expected/verify__status_not_a_claim.json | 51 ++ ...ify__status_not_a_claim_after_a_while.json | 51 ++ .../verify__status_not_yours_404.json | 21 + .../verify__status_older_run_completed.json | 203 +++++ ...rify__status_older_run_failed_crashed.json | 51 ++ ...lder_run_failed_insufficient_evidence.json | 51 ++ .../verify__status_older_run_in_progress.json | 51 ++ .../expected/verify__status_processing.json | 51 ++ ...rify__status_processing_after_a_while.json | 51 ++ .../expected/verify__status_task_stuck.json | 51 ++ .../expected/verify__status_unknown_404.json | 21 + .../parity/expected/verify__submit_202.json | 9 + .../expected/verify__submit_202_options.json | 9 + .../verify__submit_202_text_alias.json | 9 + .../expected/verify__unauthenticated_401.json | 21 + .../expected/verify__verification_200.json | 92 ++ .../verify__verification_200_covered.json | 90 ++ ...dified_at_crosses_midnight_by_minutes.json | 92 ++ ...fy__verification_200_modified_at_null.json | 92 ++ ..._200_modified_at_same_day_hours_apart.json | 92 ++ ...ify__verification_200_modified_at_set.json | 92 ++ ...ation_200_result_json_conclusion_only.json | 53 ++ ...y__verification_200_result_json_empty.json | 53 ++ ...ion_200_result_json_old_shape_strings.json | 69 ++ .../expected/verify__verification_404.json | 21 + .../verify__verification_by_task_id_200.json | 92 ++ .../verify__verification_failed_409.json | 26 + ..._failed_409_not_a_claim_after_a_while.json | 26 + .../verify__verification_not_ready_409.json | 24 + .../verify__verification_not_yours_404.json | 21 + ...verify__verification_public_anonymous.json | 80 ++ ...__verification_public_of_another_user.json | 92 ++ ...verify__verification_unknown_task_404.json | 21 + ...rification_zero_retention_expired_410.json | 22 + ...y__verification_zero_retention_served.json | 92 ++ .../webhook__certificate_timestamped.json | 23 + ..._certificate_timestamped_review_child.json | 23 + .../webhook__citecheck_completed.json | 135 +++ .../expected/webhook__citecheck_failed.json | 48 ++ .../expected/webhook__review_completed.json | 157 ++++ ...ook__review_completed_key_default_url.json | 106 +++ ...k__review_completed_oversized_rebuilt.json | 15 + .../expected/webhook__review_failed.json | 74 ++ .../webhook__verification_completed.json | 103 +++ ...hook__verification_completed_in_batch.json | 103 +++ ...dified_at_crosses_midnight_by_minutes.json | 103 +++ ...eted_modified_at_same_day_hours_apart.json | 103 +++ ...fication_failed_insufficient_evidence.json | 15 + ...hook__verification_failed_not_a_claim.json | 15 + ...ification_failed_upstream_unavailable.json | 15 + ..._verification_needs_input_multi_claim.json | 27 + .../parity/legacy/account__library_empty.json | 14 + ...dified_at_crosses_midnight_by_minutes.json | 30 + ...item_modified_at_same_day_hours_apart.json | 30 + .../parity/legacy/account__library_items.json | 60 ++ .../legacy/account__library_no_match.json | 14 + .../account__library_page_past_end.json | 14 + ...ccount__library_paginated_second_page.json | 45 + .../account__me_usage_extra_credits.json | 66 ++ .../legacy/account__me_usage_extra_only.json | 66 ++ .../account__me_usage_extract_calls.json | 66 ++ .../parity/legacy/account__me_usage_free.json | 66 ++ .../account__me_usage_free_partly_spent.json | 66 ++ .../parity/legacy/account__me_usage_plus.json | 66 ++ .../parity/legacy/account__me_usage_pro.json | 66 ++ .../legacy/account__me_usage_pro_extra.json | 66 ++ .../account__me_usage_stale_quota_row.json | 66 ++ .../parity/legacy/assess__401_no_key.json | 11 + .../parity/legacy/assess__402_no_credits.json | 19 + .../parity/legacy/assess__422_blank_item.json | 12 + .../parity/legacy/assess__422_blank_text.json | 11 + .../legacy/assess__422_input_conflict.json | 12 + .../legacy/assess__422_item_too_long.json | 12 + .../legacy/assess__422_no_input_field.json | 21 + .../legacy/assess__422_too_many_items.json | 12 + .../legacy/assess__422_wrong_type_claim.json | 21 + .../legacy/assess__422_wrong_type_claims.json | 21 + .../legacy/assess__502_framing_failed.json | 13 + .../parity/legacy/assess__503_capacity.json | 15 + ...ss__503_list_all_upstream_unavailable.json | 15 + .../assess__503_upstream_unavailable.json | 15 + .../parity/legacy/assess__deep_tier_hit.json | 28 + .../assess__idempotency_body_mismatch.json | 11 + .../legacy/assess__idempotency_first.json | 28 + .../legacy/assess__idempotency_replay.json | 28 + .../legacy/assess__list_all_error_rows.json | 42 + .../legacy/assess__list_compound_item.json | 45 + .../legacy/assess__list_mixed_rows.json | 70 ++ .../parity/legacy/assess__memo_hit.json | 28 + .../legacy/assess__replay_later_200.json | 28 + .../legacy/assess__single_no_claim.json | 15 + .../legacy/assess__single_one_claim.json | 28 + ...ss__single_text_over_wave_more_claims.json | 297 +++++++ .../assess__single_text_several_claims.json | 56 ++ .../legacy/assess__suggest_rewrite.json | 42 + .../legacy/citecheck__402_no_credits.json | 19 + .../legacy/citecheck__422_empty_body.json | 21 + .../legacy/citecheck__422_invalid_doi.json | 24 + .../citecheck__422_max_citations_over_20.json | 22 + ...techeck__422_max_citations_with_pairs.json | 21 + .../citecheck__422_pair_bad_url_scheme.json | 24 + .../legacy/citecheck__422_pair_no_source.json | 23 + .../citecheck__422_pair_url_and_doi.json | 23 + .../legacy/citecheck__422_pairs_empty.json | 22 + .../legacy/citecheck__422_pairs_over_20.json | 22 + ...citecheck__422_quote_not_in_statement.json | 23 + .../legacy/citecheck__422_text_and_pairs.json | 21 + .../legacy/citecheck__422_unknown_field.json | 24 + .../legacy/citecheck__422_url_input.json | 21 + .../citecheck__429_citecheck_in_flight.json | 14 + .../legacy/citecheck__503_capacity.json | 15 + .../citecheck__503_citations_unavailable.json | 15 + .../legacy/citecheck__get_404_not_found.json | 12 + .../legacy/citecheck__get_404_review_id.json | 12 + .../legacy/citecheck__get_410_purged.json | 13 + .../legacy/citecheck__get_checking.json | 103 +++ .../citecheck__get_completed_clean.json | 111 +++ .../citecheck__get_completed_doi_pair.json | 76 ++ .../citecheck__get_completed_incomplete.json | 127 +++ ...citecheck__get_completed_issues_found.json | 141 +++ ...check__get_completed_partly_supported.json | 111 +++ .../citecheck__get_completed_unchecked.json | 111 +++ .../citecheck__get_failed_no_citations.json | 42 + ...heck__get_failed_upstream_unavailable.json | 148 ++++ .../parity/legacy/citecheck__get_queued.json | 72 ++ ...heck__get_text_limit_exactly_at_limit.json | 119 +++ .../citecheck__get_text_limit_reached.json | 93 ++ ...echeck__idempotency_body_mismatch_422.json | 20 + .../citecheck__idempotency_conflict_409.json | 13 + .../citecheck__idempotent_replay_202.json | 14 + .../parity/legacy/citecheck__receipt_202.json | 14 + ...echeck__receipt_202_empty_webhook_url.json | 14 + .../legacy/errors__ask_bad_language.json | 11 + .../legacy/errors__ask_empty_message.json | 11 + .../parity/legacy/errors__ask_failed.json | 13 + .../errors__ask_idempotency_key_reused.json | 11 + .../legacy/errors__ask_message_too_long.json | 11 + .../legacy/errors__ask_not_completed.json | 11 + .../legacy/errors__ask_reset_not_found.json | 11 + .../legacy/errors__ask_send_not_found.json | 11 + .../parity/legacy/errors__auth_bad_key.json | 11 + .../legacy/errors__auth_basic_scheme.json | 11 + .../errors__auth_insufficient_scope.json | 14 + .../legacy/errors__auth_missing_bearer.json | 11 + .../errors__auth_missing_bearer_post.json | 11 + ...rrors__auth_private_claim_ask_history.json | 13 + .../errors__auth_private_claim_ask_send.json | 13 + .../errors__auth_unrecognised_prefix.json | 11 + ...rrors__http_error_library_bad_curated.json | 11 + ...rrors__http_error_library_bad_verdict.json | 11 + .../parity/legacy/errors__not_found_ask.json | 11 + .../legacy/errors__not_found_route.json | 11 + .../errors__not_found_verification.json | 11 + .../errors__not_found_verify_status.json | 11 + .../legacy/errors__payment_required_ask.json | 19 + .../errors__payment_required_assess.json | 19 + .../errors__payment_required_verify.json | 19 + ...__payment_required_verify_batch_short.json | 20 + .../legacy/errors__rate_limited_extract.json | 17 + .../errors__service_unavailable_ask.json | 15 + .../errors__service_unavailable_capacity.json | 15 + .../errors__validation_malformed_json.json | 11 + ...errors__validation_missing_field_hint.json | 27 + ...errors__validation_unknown_field_only.json | 26 + ...__validation_unknown_field_wrong_type.json | 25 + .../legacy/errors__validation_wrong_type.json | 21 + .../parity/legacy/extract__401_no_key.json | 11 + .../legacy/extract__422_blank_text.json | 11 + .../legacy/extract__422_focus_too_long.json | 11 + .../legacy/extract__422_missing_text.json | 21 + .../legacy/extract__429_daily_limit.json | 17 + .../extract__502_extraction_failed.json | 13 + .../extract__503_upstream_unavailable.json | 15 + .../parity/legacy/extract__focus_ready.json | 28 + ...xtract__idempotency_body_mismatch_422.json | 11 + .../legacy/extract__idempotency_replay.json | 31 + .../legacy/extract__locate_all_dropped.json | 28 + .../parity/legacy/extract__locate_failed.json | 31 + .../extract__locate_leading_whitespace.json | 39 + .../legacy/extract__locate_some_dropped.json | 52 ++ .../parity/legacy/extract__locate_true.json | 52 ++ .../legacy/extract__no_match_with_focus.json | 19 + .../parity/legacy/extract__not_a_claim.json | 19 + .../extract__not_a_claim_beside_claims.json | 28 + .../legacy/extract__ready_one_claim.json | 28 + .../legacy/extract__ready_several_claims.json | 31 + .../legacy/extract__replay_later_200.json | 31 + .../extract__url_fetch_502_unreadable.json | 13 + .../extract__url_fetch_503_upstream.json | 15 + .../legacy/extract__url_input_located.json | 39 + .../legacy/review__401_no_credentials.json | 11 + .../parity/legacy/review__402_no_credits.json | 19 + .../review__402_no_credits_exhausted.json | 19 + .../parity/legacy/review__422_blank_text.json | 21 + .../review__422_citations_options_object.json | 22 + .../legacy/review__422_depth_unknown.json | 23 + .../review__422_invalid_confidence_band.json | 23 + .../review__422_invalid_verdict_label.json | 23 + .../review__422_max_assessments_negative.json | 23 + .../review__422_max_citations_negative.json | 23 + .../review__422_max_citations_too_big.json | 23 + ...review__422_max_verifications_too_big.json | 23 + .../legacy/review__422_text_missing.json | 22 + .../legacy/review__422_text_wrong_type.json | 22 + .../review__422_unknown_escalate_field.json | 23 + .../review__422_unknown_top_level_field.json | 22 + .../review__422_unsupported_language.json | 21 + .../legacy/review__422_visibility_public.json | 22 + .../review__429_extract_daily_limit.json | 17 + .../legacy/review__429_review_in_flight.json | 14 + .../parity/legacy/review__503_capacity.json | 15 + .../review__503_citations_capacity.json | 15 + .../review__get_403_insufficient_scope.json | 14 + .../legacy/review__get_404_not_found.json | 12 + .../legacy/review__get_404_other_account.json | 12 + .../parity/legacy/review__get_410_purged.json | 13 + .../legacy/review__get_422_unknown_view.json | 21 + .../parity/legacy/review__get_assessing.json | 110 +++ ...view__get_assessment_rows_full_fields.json | 170 ++++ .../legacy/review__get_citations_clean.json | 183 ++++ ...w__get_citations_failed_and_unchecked.json | 199 +++++ .../review__get_citations_issue_full.json | 205 +++++ ...view__get_citations_issue_issues_view.json | 93 ++ ..._get_citations_limit_exactly_at_limit.json | 183 ++++ .../review__get_citations_limit_reached.json | 157 ++++ ..._get_citations_no_claim_but_citations.json | 152 ++++ ...w__get_citations_no_claim_no_citation.json | 68 ++ .../review__get_citations_not_asked.json | 100 +++ .../legacy/review__get_citations_only.json | 159 ++++ ...eview__get_citations_partly_supported.json | 183 ++++ .../legacy/review__get_citations_running.json | 167 ++++ ...w__get_citations_skipped_switched_off.json | 100 +++ ...view__get_citations_skipped_url_input.json | 68 ++ .../review__get_claim_limit_not_reached.json | 130 +++ ...review__get_claim_limit_reached_exact.json | 130 +++ .../review__get_completed_assess_only.json | 156 ++++ .../legacy/review__get_completed_clean.json | 130 +++ ...ew__get_completed_issues_all_verified.json | 261 ++++++ .../review__get_completed_issues_full.json | 312 +++++++ ...iew__get_completed_issues_view_issues.json | 133 +++ .../review__get_completed_positions.json | 142 +++ ...review__get_completed_recovered_claim.json | 100 +++ ...ew__get_completed_with_untraced_claim.json | 142 +++ .../review__get_during_quick_check.json | 88 ++ ...w__get_failed_every_assessment_failed.json | 157 ++++ .../legacy/review__get_failed_no_claim.json | 68 ++ .../review__get_failed_no_claim_untraced.json | 68 ++ .../legacy/review__get_more_claims.json | 155 ++++ ...dified_at_crosses_midnight_by_minutes.json | 151 ++++ ...tion_modified_at_same_day_hours_apart.json | 151 ++++ .../legacy/review__get_policy_resolved.json | 98 +++ .../parity/legacy/review__get_queued.json | 62 ++ .../legacy/review__get_suggested_edits.json | 269 ++++++ ...view__get_suggested_edits_issues_view.json | 128 +++ .../parity/legacy/review__get_url_review.json | 106 +++ .../parity/legacy/review__get_verifying.json | 179 ++++ ...review__idempotency_body_mismatch_422.json | 20 + .../review__idempotency_conflict_409.json | 13 + ...mpotency_conflict_409_existing_review.json | 13 + .../legacy/review__idempotent_replay_202.json | 14 + .../parity/legacy/review__receipt_202.json | 14 + ...review__receipt_202_empty_webhook_url.json | 14 + .../review__receipt_202_webhook_url.json | 14 + .../legacy/review__replay_later_202.json | 14 + .../parity/legacy/verify__batch_202.json | 21 + .../legacy/verify__batch_capacity_503.json | 15 + .../legacy/verify__batch_empty_422.json | 11 + ...erify__batch_idempotency_conflict_409.json | 12 + .../verify__batch_item_missing_claim_422.json | 23 + .../legacy/verify__batch_no_credits_402.json | 20 + .../legacy/verify__batch_partial_202.json | 18 + .../legacy/verify__batch_too_many_422.json | 11 + .../legacy/verify__blank_claim_422.json | 11 + .../parity/legacy/verify__capacity_503.json | 15 + ...verify__idempotency_body_mismatch_422.json | 11 + .../verify__idempotency_conflict_409.json | 12 + .../verify__idempotency_key_replay.json | 13 + .../legacy/verify__implicit_dedup_200.json | 12 + .../verify__implicit_repeat_replay.json | 13 + .../legacy/verify__invalid_depth_422.json | 24 + .../legacy/verify__invalid_language_422.json | 11 + .../parity/legacy/verify__list_200.json | 45 + ...dified_at_crosses_midnight_by_minutes.json | 30 + ..._200_modified_at_same_day_hours_apart.json | 30 + .../legacy/verify__list_clamped_200.json | 14 + .../parity/legacy/verify__list_empty_200.json | 14 + .../parity/legacy/verify__list_page2_200.json | 30 + .../legacy/verify__misnamed_field_422.json | 26 + .../legacy/verify__missing_claim_422.json | 21 + .../parity/legacy/verify__no_credits_402.json | 19 + .../legacy/verify__replay_later_202.json | 13 + .../parity/legacy/verify__select_202.json | 21 + .../legacy/verify__select_empty_422.json | 11 + .../verify__select_invalid_selection_422.json | 13 + ...rify__select_no_selection_pending_409.json | 13 + .../legacy/verify__select_too_many_422.json | 11 + .../verify__select_unknown_task_404.json | 11 + ...erify__status_cancelled_after_a_while.json | 17 + .../legacy/verify__status_completed.json | 99 +++ ...erify__status_completed_after_a_while.json | 99 +++ ...dified_at_crosses_midnight_by_minutes.json | 99 +++ ...hile_modified_at_same_day_hours_apart.json | 99 +++ ...dified_at_crosses_midnight_by_minutes.json | 99 +++ ...eted_modified_at_same_day_hours_apart.json | 99 +++ .../parity/legacy/verify__status_failed.json | 17 + .../verify__status_failed_after_a_while.json | 17 + ...__status_failed_after_a_while_framing.json | 17 + .../verify__status_failed_retryable.json | 17 + .../legacy/verify__status_needs_input.json | 24 + .../legacy/verify__status_not_a_claim.json | 18 + ...ify__status_not_a_claim_after_a_while.json | 17 + .../legacy/verify__status_not_yours_404.json | 11 + .../verify__status_older_run_completed.json | 99 +++ ...rify__status_older_run_failed_crashed.json | 17 + ...lder_run_failed_insufficient_evidence.json | 17 + .../verify__status_older_run_in_progress.json | 19 + .../legacy/verify__status_processing.json | 19 + ...rify__status_processing_after_a_while.json | 19 + .../legacy/verify__status_task_stuck.json | 17 + .../legacy/verify__status_unknown_404.json | 11 + .../parity/legacy/verify__submit_202.json | 13 + .../legacy/verify__submit_202_options.json | 13 + .../legacy/verify__submit_202_text_alias.json | 13 + .../legacy/verify__unauthenticated_401.json | 11 + .../legacy/verify__verification_200.json | 95 +++ .../verify__verification_200_covered.json | 93 ++ ...dified_at_crosses_midnight_by_minutes.json | 95 +++ ...fy__verification_200_modified_at_null.json | 95 +++ ..._200_modified_at_same_day_hours_apart.json | 95 +++ ...ify__verification_200_modified_at_set.json | 95 +++ ...ation_200_result_json_conclusion_only.json | 56 ++ ...y__verification_200_result_json_empty.json | 56 ++ ...ion_200_result_json_old_shape_strings.json | 72 ++ .../legacy/verify__verification_404.json | 11 + .../verify__verification_by_task_id_200.json | 95 +++ .../verify__verification_failed_409.json | 19 + ..._failed_409_not_a_claim_after_a_while.json | 19 + .../verify__verification_not_ready_409.json | 15 + .../verify__verification_not_yours_404.json | 11 + ...verify__verification_public_anonymous.json | 83 ++ ...__verification_public_of_another_user.json | 95 +++ ...verify__verification_unknown_task_404.json | 12 + ...rification_zero_retention_expired_410.json | 13 + ...y__verification_zero_retention_served.json | 95 +++ .../webhook__certificate_timestamped.json | 27 + ..._certificate_timestamped_review_child.json | 28 + .../legacy/webhook__citecheck_completed.json | 134 +++ .../legacy/webhook__citecheck_failed.json | 47 + .../legacy/webhook__review_completed.json | 156 ++++ ...ook__review_completed_key_default_url.json | 105 +++ ...k__review_completed_oversized_rebuilt.json | 11 + .../parity/legacy/webhook__review_failed.json | 73 ++ .../webhook__verification_completed.json | 107 +++ ...hook__verification_completed_in_batch.json | 107 +++ ...dified_at_crosses_midnight_by_minutes.json | 107 +++ ...eted_modified_at_same_day_hours_apart.json | 107 +++ ...fication_failed_insufficient_evidence.json | 19 + ...hook__verification_failed_not_a_claim.json | 19 + ...ification_failed_upstream_unavailable.json | 19 + ..._verification_needs_input_multi_claim.json | 30 + tests/fixtures/parity/requests.json | 68 ++ tests/parity_generate.py | 37 + tests/parity_observe.py | 233 +++++ tests/parity_requests.py | 99 +++ tests/test_cli.py | 2 +- tests/test_input_aliases.py | 3 +- tests/test_parity.py | 207 +++++ tests/test_read_both_shapes.py | 369 ++++++++ tests/test_usage_models.py | 12 +- 946 files changed, 48372 insertions(+), 312 deletions(-) create mode 100644 tests/fixtures/parity/canonical/account__library_empty.json create mode 100644 tests/fixtures/parity/canonical/account__library_item_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/canonical/account__library_item_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/canonical/account__library_items.json create mode 100644 tests/fixtures/parity/canonical/account__library_no_match.json create mode 100644 tests/fixtures/parity/canonical/account__library_page_past_end.json create mode 100644 tests/fixtures/parity/canonical/account__library_paginated_second_page.json create mode 100644 tests/fixtures/parity/canonical/account__me_usage_extra_credits.json create mode 100644 tests/fixtures/parity/canonical/account__me_usage_extra_only.json create mode 100644 tests/fixtures/parity/canonical/account__me_usage_extract_calls.json create mode 100644 tests/fixtures/parity/canonical/account__me_usage_free.json create mode 100644 tests/fixtures/parity/canonical/account__me_usage_free_partly_spent.json create mode 100644 tests/fixtures/parity/canonical/account__me_usage_plus.json create mode 100644 tests/fixtures/parity/canonical/account__me_usage_pro.json create mode 100644 tests/fixtures/parity/canonical/account__me_usage_pro_extra.json create mode 100644 tests/fixtures/parity/canonical/account__me_usage_stale_quota_row.json create mode 100644 tests/fixtures/parity/canonical/assess__401_no_key.json create mode 100644 tests/fixtures/parity/canonical/assess__402_no_credits.json create mode 100644 tests/fixtures/parity/canonical/assess__422_blank_item.json create mode 100644 tests/fixtures/parity/canonical/assess__422_blank_text.json create mode 100644 tests/fixtures/parity/canonical/assess__422_input_conflict.json create mode 100644 tests/fixtures/parity/canonical/assess__422_item_too_long.json create mode 100644 tests/fixtures/parity/canonical/assess__422_no_input_field.json create mode 100644 tests/fixtures/parity/canonical/assess__422_too_many_items.json create mode 100644 tests/fixtures/parity/canonical/assess__422_wrong_type_claim.json create mode 100644 tests/fixtures/parity/canonical/assess__422_wrong_type_claims.json create mode 100644 tests/fixtures/parity/canonical/assess__502_framing_failed.json create mode 100644 tests/fixtures/parity/canonical/assess__503_capacity.json create mode 100644 tests/fixtures/parity/canonical/assess__503_list_all_upstream_unavailable.json create mode 100644 tests/fixtures/parity/canonical/assess__503_upstream_unavailable.json create mode 100644 tests/fixtures/parity/canonical/assess__deep_tier_hit.json create mode 100644 tests/fixtures/parity/canonical/assess__idempotency_body_mismatch.json create mode 100644 tests/fixtures/parity/canonical/assess__idempotency_first.json create mode 100644 tests/fixtures/parity/canonical/assess__idempotency_replay.json create mode 100644 tests/fixtures/parity/canonical/assess__list_all_error_rows.json create mode 100644 tests/fixtures/parity/canonical/assess__list_compound_item.json create mode 100644 tests/fixtures/parity/canonical/assess__list_mixed_rows.json create mode 100644 tests/fixtures/parity/canonical/assess__memo_hit.json create mode 100644 tests/fixtures/parity/canonical/assess__replay_later_200.json create mode 100644 tests/fixtures/parity/canonical/assess__single_no_claim.json create mode 100644 tests/fixtures/parity/canonical/assess__single_one_claim.json create mode 100644 tests/fixtures/parity/canonical/assess__single_text_over_wave_more_claims.json create mode 100644 tests/fixtures/parity/canonical/assess__single_text_several_claims.json create mode 100644 tests/fixtures/parity/canonical/assess__suggest_rewrite.json create mode 100644 tests/fixtures/parity/canonical/citecheck__402_no_credits.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_empty_body.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_invalid_doi.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_max_citations_over_20.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_max_citations_with_pairs.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_pair_bad_url_scheme.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_pair_no_source.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_pair_url_and_doi.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_pairs_empty.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_pairs_over_20.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_quote_not_in_statement.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_text_and_pairs.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_unknown_field.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_url_input.json create mode 100644 tests/fixtures/parity/canonical/citecheck__429_citecheck_in_flight.json create mode 100644 tests/fixtures/parity/canonical/citecheck__503_capacity.json create mode 100644 tests/fixtures/parity/canonical/citecheck__503_citations_unavailable.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_404_not_found.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_404_review_id.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_410_purged.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_checking.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_completed_clean.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_completed_doi_pair.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_completed_incomplete.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_completed_issues_found.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_completed_partly_supported.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_completed_unchecked.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_failed_no_citations.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_failed_upstream_unavailable.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_queued.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_text_limit_exactly_at_limit.json create mode 100644 tests/fixtures/parity/canonical/citecheck__get_text_limit_reached.json create mode 100644 tests/fixtures/parity/canonical/citecheck__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/canonical/citecheck__idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/canonical/citecheck__idempotent_replay_202.json create mode 100644 tests/fixtures/parity/canonical/citecheck__receipt_202.json create mode 100644 tests/fixtures/parity/canonical/citecheck__receipt_202_empty_webhook_url.json create mode 100644 tests/fixtures/parity/canonical/errors__ask_bad_language.json create mode 100644 tests/fixtures/parity/canonical/errors__ask_empty_message.json create mode 100644 tests/fixtures/parity/canonical/errors__ask_failed.json create mode 100644 tests/fixtures/parity/canonical/errors__ask_idempotency_key_reused.json create mode 100644 tests/fixtures/parity/canonical/errors__ask_message_too_long.json create mode 100644 tests/fixtures/parity/canonical/errors__ask_not_completed.json create mode 100644 tests/fixtures/parity/canonical/errors__ask_reset_not_found.json create mode 100644 tests/fixtures/parity/canonical/errors__ask_send_not_found.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_bad_key.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_basic_scheme.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_insufficient_scope.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_missing_bearer.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_missing_bearer_post.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_private_claim_ask_history.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_private_claim_ask_send.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_unrecognised_prefix.json create mode 100644 tests/fixtures/parity/canonical/errors__http_error_library_bad_curated.json create mode 100644 tests/fixtures/parity/canonical/errors__http_error_library_bad_verdict.json create mode 100644 tests/fixtures/parity/canonical/errors__not_found_ask.json create mode 100644 tests/fixtures/parity/canonical/errors__not_found_route.json create mode 100644 tests/fixtures/parity/canonical/errors__not_found_verification.json create mode 100644 tests/fixtures/parity/canonical/errors__not_found_verify_status.json create mode 100644 tests/fixtures/parity/canonical/errors__payment_required_ask.json create mode 100644 tests/fixtures/parity/canonical/errors__payment_required_assess.json create mode 100644 tests/fixtures/parity/canonical/errors__payment_required_verify.json create mode 100644 tests/fixtures/parity/canonical/errors__payment_required_verify_batch_short.json create mode 100644 tests/fixtures/parity/canonical/errors__rate_limited_extract.json create mode 100644 tests/fixtures/parity/canonical/errors__service_unavailable_ask.json create mode 100644 tests/fixtures/parity/canonical/errors__service_unavailable_capacity.json create mode 100644 tests/fixtures/parity/canonical/errors__validation_malformed_json.json create mode 100644 tests/fixtures/parity/canonical/errors__validation_missing_field_hint.json create mode 100644 tests/fixtures/parity/canonical/errors__validation_unknown_field_only.json create mode 100644 tests/fixtures/parity/canonical/errors__validation_unknown_field_wrong_type.json create mode 100644 tests/fixtures/parity/canonical/errors__validation_wrong_type.json create mode 100644 tests/fixtures/parity/canonical/extract__401_no_key.json create mode 100644 tests/fixtures/parity/canonical/extract__422_blank_text.json create mode 100644 tests/fixtures/parity/canonical/extract__422_focus_too_long.json create mode 100644 tests/fixtures/parity/canonical/extract__422_missing_text.json create mode 100644 tests/fixtures/parity/canonical/extract__429_daily_limit.json create mode 100644 tests/fixtures/parity/canonical/extract__502_extraction_failed.json create mode 100644 tests/fixtures/parity/canonical/extract__503_upstream_unavailable.json create mode 100644 tests/fixtures/parity/canonical/extract__focus_ready.json create mode 100644 tests/fixtures/parity/canonical/extract__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/canonical/extract__idempotency_replay.json create mode 100644 tests/fixtures/parity/canonical/extract__locate_all_dropped.json create mode 100644 tests/fixtures/parity/canonical/extract__locate_failed.json create mode 100644 tests/fixtures/parity/canonical/extract__locate_leading_whitespace.json create mode 100644 tests/fixtures/parity/canonical/extract__locate_some_dropped.json create mode 100644 tests/fixtures/parity/canonical/extract__locate_true.json create mode 100644 tests/fixtures/parity/canonical/extract__no_match_with_focus.json create mode 100644 tests/fixtures/parity/canonical/extract__not_a_claim.json create mode 100644 tests/fixtures/parity/canonical/extract__not_a_claim_beside_claims.json create mode 100644 tests/fixtures/parity/canonical/extract__ready_one_claim.json create mode 100644 tests/fixtures/parity/canonical/extract__ready_several_claims.json create mode 100644 tests/fixtures/parity/canonical/extract__replay_later_200.json create mode 100644 tests/fixtures/parity/canonical/extract__url_fetch_502_unreadable.json create mode 100644 tests/fixtures/parity/canonical/extract__url_fetch_503_upstream.json create mode 100644 tests/fixtures/parity/canonical/extract__url_input_located.json create mode 100644 tests/fixtures/parity/canonical/review__401_no_credentials.json create mode 100644 tests/fixtures/parity/canonical/review__402_no_credits.json create mode 100644 tests/fixtures/parity/canonical/review__402_no_credits_exhausted.json create mode 100644 tests/fixtures/parity/canonical/review__422_blank_text.json create mode 100644 tests/fixtures/parity/canonical/review__422_citations_options_object.json create mode 100644 tests/fixtures/parity/canonical/review__422_depth_unknown.json create mode 100644 tests/fixtures/parity/canonical/review__422_invalid_confidence_band.json create mode 100644 tests/fixtures/parity/canonical/review__422_invalid_verdict_label.json create mode 100644 tests/fixtures/parity/canonical/review__422_max_assessments_negative.json create mode 100644 tests/fixtures/parity/canonical/review__422_max_citations_negative.json create mode 100644 tests/fixtures/parity/canonical/review__422_max_citations_too_big.json create mode 100644 tests/fixtures/parity/canonical/review__422_max_verifications_too_big.json create mode 100644 tests/fixtures/parity/canonical/review__422_text_missing.json create mode 100644 tests/fixtures/parity/canonical/review__422_text_wrong_type.json create mode 100644 tests/fixtures/parity/canonical/review__422_unknown_escalate_field.json create mode 100644 tests/fixtures/parity/canonical/review__422_unknown_top_level_field.json create mode 100644 tests/fixtures/parity/canonical/review__422_unsupported_language.json create mode 100644 tests/fixtures/parity/canonical/review__422_visibility_public.json create mode 100644 tests/fixtures/parity/canonical/review__429_extract_daily_limit.json create mode 100644 tests/fixtures/parity/canonical/review__429_review_in_flight.json create mode 100644 tests/fixtures/parity/canonical/review__503_capacity.json create mode 100644 tests/fixtures/parity/canonical/review__503_citations_capacity.json create mode 100644 tests/fixtures/parity/canonical/review__get_403_insufficient_scope.json create mode 100644 tests/fixtures/parity/canonical/review__get_404_not_found.json create mode 100644 tests/fixtures/parity/canonical/review__get_404_other_account.json create mode 100644 tests/fixtures/parity/canonical/review__get_410_purged.json create mode 100644 tests/fixtures/parity/canonical/review__get_422_unknown_view.json create mode 100644 tests/fixtures/parity/canonical/review__get_assessing.json create mode 100644 tests/fixtures/parity/canonical/review__get_assessment_rows_full_fields.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_clean.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_failed_and_unchecked.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_issue_full.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_issue_issues_view.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_limit_exactly_at_limit.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_limit_reached.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_no_claim_but_citations.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_no_claim_no_citation.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_not_asked.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_only.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_partly_supported.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_running.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_skipped_switched_off.json create mode 100644 tests/fixtures/parity/canonical/review__get_citations_skipped_url_input.json create mode 100644 tests/fixtures/parity/canonical/review__get_claim_limit_not_reached.json create mode 100644 tests/fixtures/parity/canonical/review__get_claim_limit_reached_exact.json create mode 100644 tests/fixtures/parity/canonical/review__get_completed_assess_only.json create mode 100644 tests/fixtures/parity/canonical/review__get_completed_clean.json create mode 100644 tests/fixtures/parity/canonical/review__get_completed_issues_all_verified.json create mode 100644 tests/fixtures/parity/canonical/review__get_completed_issues_full.json create mode 100644 tests/fixtures/parity/canonical/review__get_completed_issues_view_issues.json create mode 100644 tests/fixtures/parity/canonical/review__get_completed_positions.json create mode 100644 tests/fixtures/parity/canonical/review__get_completed_recovered_claim.json create mode 100644 tests/fixtures/parity/canonical/review__get_completed_with_untraced_claim.json create mode 100644 tests/fixtures/parity/canonical/review__get_during_quick_check.json create mode 100644 tests/fixtures/parity/canonical/review__get_failed_every_assessment_failed.json create mode 100644 tests/fixtures/parity/canonical/review__get_failed_no_claim.json create mode 100644 tests/fixtures/parity/canonical/review__get_failed_no_claim_untraced.json create mode 100644 tests/fixtures/parity/canonical/review__get_more_claims.json create mode 100644 tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/canonical/review__get_policy_resolved.json create mode 100644 tests/fixtures/parity/canonical/review__get_queued.json create mode 100644 tests/fixtures/parity/canonical/review__get_suggested_edits.json create mode 100644 tests/fixtures/parity/canonical/review__get_suggested_edits_issues_view.json create mode 100644 tests/fixtures/parity/canonical/review__get_url_review.json create mode 100644 tests/fixtures/parity/canonical/review__get_verifying.json create mode 100644 tests/fixtures/parity/canonical/review__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/canonical/review__idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/canonical/review__idempotency_conflict_409_existing_review.json create mode 100644 tests/fixtures/parity/canonical/review__idempotent_replay_202.json create mode 100644 tests/fixtures/parity/canonical/review__receipt_202.json create mode 100644 tests/fixtures/parity/canonical/review__receipt_202_empty_webhook_url.json create mode 100644 tests/fixtures/parity/canonical/review__receipt_202_webhook_url.json create mode 100644 tests/fixtures/parity/canonical/review__replay_later_202.json create mode 100644 tests/fixtures/parity/canonical/verify__batch_202.json create mode 100644 tests/fixtures/parity/canonical/verify__batch_capacity_503.json create mode 100644 tests/fixtures/parity/canonical/verify__batch_empty_422.json create mode 100644 tests/fixtures/parity/canonical/verify__batch_idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/canonical/verify__batch_item_missing_claim_422.json create mode 100644 tests/fixtures/parity/canonical/verify__batch_no_credits_402.json create mode 100644 tests/fixtures/parity/canonical/verify__batch_partial_202.json create mode 100644 tests/fixtures/parity/canonical/verify__batch_too_many_422.json create mode 100644 tests/fixtures/parity/canonical/verify__blank_claim_422.json create mode 100644 tests/fixtures/parity/canonical/verify__capacity_503.json create mode 100644 tests/fixtures/parity/canonical/verify__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/canonical/verify__idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/canonical/verify__idempotency_key_replay.json create mode 100644 tests/fixtures/parity/canonical/verify__implicit_dedup_200.json create mode 100644 tests/fixtures/parity/canonical/verify__implicit_repeat_replay.json create mode 100644 tests/fixtures/parity/canonical/verify__invalid_depth_422.json create mode 100644 tests/fixtures/parity/canonical/verify__invalid_language_422.json create mode 100644 tests/fixtures/parity/canonical/verify__list_200.json create mode 100644 tests/fixtures/parity/canonical/verify__list_200_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/canonical/verify__list_200_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/canonical/verify__list_clamped_200.json create mode 100644 tests/fixtures/parity/canonical/verify__list_empty_200.json create mode 100644 tests/fixtures/parity/canonical/verify__list_page2_200.json create mode 100644 tests/fixtures/parity/canonical/verify__misnamed_field_422.json create mode 100644 tests/fixtures/parity/canonical/verify__missing_claim_422.json create mode 100644 tests/fixtures/parity/canonical/verify__no_credits_402.json create mode 100644 tests/fixtures/parity/canonical/verify__replay_later_202.json create mode 100644 tests/fixtures/parity/canonical/verify__select_202.json create mode 100644 tests/fixtures/parity/canonical/verify__select_empty_422.json create mode 100644 tests/fixtures/parity/canonical/verify__select_invalid_selection_422.json create mode 100644 tests/fixtures/parity/canonical/verify__select_no_selection_pending_409.json create mode 100644 tests/fixtures/parity/canonical/verify__select_too_many_422.json create mode 100644 tests/fixtures/parity/canonical/verify__select_unknown_task_404.json create mode 100644 tests/fixtures/parity/canonical/verify__status_cancelled_after_a_while.json create mode 100644 tests/fixtures/parity/canonical/verify__status_completed.json create mode 100644 tests/fixtures/parity/canonical/verify__status_completed_after_a_while.json create mode 100644 tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/canonical/verify__status_completed_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/canonical/verify__status_completed_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/canonical/verify__status_failed.json create mode 100644 tests/fixtures/parity/canonical/verify__status_failed_after_a_while.json create mode 100644 tests/fixtures/parity/canonical/verify__status_failed_after_a_while_framing.json create mode 100644 tests/fixtures/parity/canonical/verify__status_failed_retryable.json create mode 100644 tests/fixtures/parity/canonical/verify__status_needs_input.json create mode 100644 tests/fixtures/parity/canonical/verify__status_not_a_claim.json create mode 100644 tests/fixtures/parity/canonical/verify__status_not_a_claim_after_a_while.json create mode 100644 tests/fixtures/parity/canonical/verify__status_not_yours_404.json create mode 100644 tests/fixtures/parity/canonical/verify__status_older_run_completed.json create mode 100644 tests/fixtures/parity/canonical/verify__status_older_run_failed_crashed.json create mode 100644 tests/fixtures/parity/canonical/verify__status_older_run_failed_insufficient_evidence.json create mode 100644 tests/fixtures/parity/canonical/verify__status_older_run_in_progress.json create mode 100644 tests/fixtures/parity/canonical/verify__status_processing.json create mode 100644 tests/fixtures/parity/canonical/verify__status_processing_after_a_while.json create mode 100644 tests/fixtures/parity/canonical/verify__status_task_stuck.json create mode 100644 tests/fixtures/parity/canonical/verify__status_unknown_404.json create mode 100644 tests/fixtures/parity/canonical/verify__submit_202.json create mode 100644 tests/fixtures/parity/canonical/verify__submit_202_options.json create mode 100644 tests/fixtures/parity/canonical/verify__submit_202_text_alias.json create mode 100644 tests/fixtures/parity/canonical/verify__unauthenticated_401.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_200.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_200_covered.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_200_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_200_modified_at_null.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_200_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_200_modified_at_set.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_200_result_json_conclusion_only.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_200_result_json_empty.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_200_result_json_old_shape_strings.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_404.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_by_task_id_200.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_failed_409.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_failed_409_not_a_claim_after_a_while.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_not_ready_409.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_not_yours_404.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_public_anonymous.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_public_of_another_user.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_unknown_task_404.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_zero_retention_expired_410.json create mode 100644 tests/fixtures/parity/canonical/verify__verification_zero_retention_served.json create mode 100644 tests/fixtures/parity/canonical/webhook__certificate_timestamped.json create mode 100644 tests/fixtures/parity/canonical/webhook__certificate_timestamped_review_child.json create mode 100644 tests/fixtures/parity/canonical/webhook__citecheck_completed.json create mode 100644 tests/fixtures/parity/canonical/webhook__citecheck_failed.json create mode 100644 tests/fixtures/parity/canonical/webhook__review_completed.json create mode 100644 tests/fixtures/parity/canonical/webhook__review_completed_key_default_url.json create mode 100644 tests/fixtures/parity/canonical/webhook__review_completed_oversized_rebuilt.json create mode 100644 tests/fixtures/parity/canonical/webhook__review_failed.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_completed.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_completed_in_batch.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_failed_insufficient_evidence.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_failed_not_a_claim.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_failed_upstream_unavailable.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_needs_input_multi_claim.json create mode 100644 tests/fixtures/parity/expected/account__library_empty.json create mode 100644 tests/fixtures/parity/expected/account__library_item_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/expected/account__library_item_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/expected/account__library_items.json create mode 100644 tests/fixtures/parity/expected/account__library_no_match.json create mode 100644 tests/fixtures/parity/expected/account__library_page_past_end.json create mode 100644 tests/fixtures/parity/expected/account__library_paginated_second_page.json create mode 100644 tests/fixtures/parity/expected/account__me_usage_extra_credits.json create mode 100644 tests/fixtures/parity/expected/account__me_usage_extra_only.json create mode 100644 tests/fixtures/parity/expected/account__me_usage_extract_calls.json create mode 100644 tests/fixtures/parity/expected/account__me_usage_free.json create mode 100644 tests/fixtures/parity/expected/account__me_usage_free_partly_spent.json create mode 100644 tests/fixtures/parity/expected/account__me_usage_plus.json create mode 100644 tests/fixtures/parity/expected/account__me_usage_pro.json create mode 100644 tests/fixtures/parity/expected/account__me_usage_pro_extra.json create mode 100644 tests/fixtures/parity/expected/account__me_usage_stale_quota_row.json create mode 100644 tests/fixtures/parity/expected/assess__401_no_key.json create mode 100644 tests/fixtures/parity/expected/assess__402_no_credits.json create mode 100644 tests/fixtures/parity/expected/assess__422_blank_item.json create mode 100644 tests/fixtures/parity/expected/assess__422_blank_text.json create mode 100644 tests/fixtures/parity/expected/assess__422_input_conflict.json create mode 100644 tests/fixtures/parity/expected/assess__422_item_too_long.json create mode 100644 tests/fixtures/parity/expected/assess__422_no_input_field.json create mode 100644 tests/fixtures/parity/expected/assess__422_too_many_items.json create mode 100644 tests/fixtures/parity/expected/assess__422_wrong_type_claim.json create mode 100644 tests/fixtures/parity/expected/assess__422_wrong_type_claims.json create mode 100644 tests/fixtures/parity/expected/assess__502_framing_failed.json create mode 100644 tests/fixtures/parity/expected/assess__503_capacity.json create mode 100644 tests/fixtures/parity/expected/assess__503_list_all_upstream_unavailable.json create mode 100644 tests/fixtures/parity/expected/assess__503_upstream_unavailable.json create mode 100644 tests/fixtures/parity/expected/assess__deep_tier_hit.json create mode 100644 tests/fixtures/parity/expected/assess__idempotency_body_mismatch.json create mode 100644 tests/fixtures/parity/expected/assess__idempotency_first.json create mode 100644 tests/fixtures/parity/expected/assess__idempotency_replay.json create mode 100644 tests/fixtures/parity/expected/assess__list_all_error_rows.json create mode 100644 tests/fixtures/parity/expected/assess__list_compound_item.json create mode 100644 tests/fixtures/parity/expected/assess__list_mixed_rows.json create mode 100644 tests/fixtures/parity/expected/assess__memo_hit.json create mode 100644 tests/fixtures/parity/expected/assess__replay_later_200.json create mode 100644 tests/fixtures/parity/expected/assess__single_no_claim.json create mode 100644 tests/fixtures/parity/expected/assess__single_one_claim.json create mode 100644 tests/fixtures/parity/expected/assess__single_text_over_wave_more_claims.json create mode 100644 tests/fixtures/parity/expected/assess__single_text_several_claims.json create mode 100644 tests/fixtures/parity/expected/assess__suggest_rewrite.json create mode 100644 tests/fixtures/parity/expected/citecheck__402_no_credits.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_empty_body.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_invalid_doi.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_max_citations_over_20.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_max_citations_with_pairs.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_pair_bad_url_scheme.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_pair_no_source.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_pair_url_and_doi.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_pairs_empty.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_pairs_over_20.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_quote_not_in_statement.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_text_and_pairs.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_unknown_field.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_url_input.json create mode 100644 tests/fixtures/parity/expected/citecheck__429_citecheck_in_flight.json create mode 100644 tests/fixtures/parity/expected/citecheck__503_capacity.json create mode 100644 tests/fixtures/parity/expected/citecheck__503_citations_unavailable.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_404_not_found.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_404_review_id.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_410_purged.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_checking.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_completed_clean.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_completed_doi_pair.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_completed_incomplete.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_completed_issues_found.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_completed_partly_supported.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_completed_unchecked.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_failed_no_citations.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_failed_upstream_unavailable.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_queued.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_text_limit_exactly_at_limit.json create mode 100644 tests/fixtures/parity/expected/citecheck__get_text_limit_reached.json create mode 100644 tests/fixtures/parity/expected/citecheck__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/expected/citecheck__idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/expected/citecheck__idempotent_replay_202.json create mode 100644 tests/fixtures/parity/expected/citecheck__receipt_202.json create mode 100644 tests/fixtures/parity/expected/citecheck__receipt_202_empty_webhook_url.json create mode 100644 tests/fixtures/parity/expected/errors__ask_bad_language.json create mode 100644 tests/fixtures/parity/expected/errors__ask_empty_message.json create mode 100644 tests/fixtures/parity/expected/errors__ask_failed.json create mode 100644 tests/fixtures/parity/expected/errors__ask_idempotency_key_reused.json create mode 100644 tests/fixtures/parity/expected/errors__ask_message_too_long.json create mode 100644 tests/fixtures/parity/expected/errors__ask_not_completed.json create mode 100644 tests/fixtures/parity/expected/errors__ask_reset_not_found.json create mode 100644 tests/fixtures/parity/expected/errors__ask_send_not_found.json create mode 100644 tests/fixtures/parity/expected/errors__auth_bad_key.json create mode 100644 tests/fixtures/parity/expected/errors__auth_basic_scheme.json create mode 100644 tests/fixtures/parity/expected/errors__auth_insufficient_scope.json create mode 100644 tests/fixtures/parity/expected/errors__auth_missing_bearer.json create mode 100644 tests/fixtures/parity/expected/errors__auth_missing_bearer_post.json create mode 100644 tests/fixtures/parity/expected/errors__auth_private_claim_ask_history.json create mode 100644 tests/fixtures/parity/expected/errors__auth_private_claim_ask_send.json create mode 100644 tests/fixtures/parity/expected/errors__auth_unrecognised_prefix.json create mode 100644 tests/fixtures/parity/expected/errors__http_error_library_bad_curated.json create mode 100644 tests/fixtures/parity/expected/errors__http_error_library_bad_verdict.json create mode 100644 tests/fixtures/parity/expected/errors__not_found_ask.json create mode 100644 tests/fixtures/parity/expected/errors__not_found_route.json create mode 100644 tests/fixtures/parity/expected/errors__not_found_verification.json create mode 100644 tests/fixtures/parity/expected/errors__not_found_verify_status.json create mode 100644 tests/fixtures/parity/expected/errors__payment_required_ask.json create mode 100644 tests/fixtures/parity/expected/errors__payment_required_assess.json create mode 100644 tests/fixtures/parity/expected/errors__payment_required_verify.json create mode 100644 tests/fixtures/parity/expected/errors__payment_required_verify_batch_short.json create mode 100644 tests/fixtures/parity/expected/errors__rate_limited_extract.json create mode 100644 tests/fixtures/parity/expected/errors__service_unavailable_ask.json create mode 100644 tests/fixtures/parity/expected/errors__service_unavailable_capacity.json create mode 100644 tests/fixtures/parity/expected/errors__validation_malformed_json.json create mode 100644 tests/fixtures/parity/expected/errors__validation_missing_field_hint.json create mode 100644 tests/fixtures/parity/expected/errors__validation_unknown_field_only.json create mode 100644 tests/fixtures/parity/expected/errors__validation_unknown_field_wrong_type.json create mode 100644 tests/fixtures/parity/expected/errors__validation_wrong_type.json create mode 100644 tests/fixtures/parity/expected/extract__401_no_key.json create mode 100644 tests/fixtures/parity/expected/extract__422_blank_text.json create mode 100644 tests/fixtures/parity/expected/extract__422_focus_too_long.json create mode 100644 tests/fixtures/parity/expected/extract__422_missing_text.json create mode 100644 tests/fixtures/parity/expected/extract__429_daily_limit.json create mode 100644 tests/fixtures/parity/expected/extract__502_extraction_failed.json create mode 100644 tests/fixtures/parity/expected/extract__503_upstream_unavailable.json create mode 100644 tests/fixtures/parity/expected/extract__focus_ready.json create mode 100644 tests/fixtures/parity/expected/extract__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/expected/extract__idempotency_replay.json create mode 100644 tests/fixtures/parity/expected/extract__locate_all_dropped.json create mode 100644 tests/fixtures/parity/expected/extract__locate_failed.json create mode 100644 tests/fixtures/parity/expected/extract__locate_leading_whitespace.json create mode 100644 tests/fixtures/parity/expected/extract__locate_some_dropped.json create mode 100644 tests/fixtures/parity/expected/extract__locate_true.json create mode 100644 tests/fixtures/parity/expected/extract__no_match_with_focus.json create mode 100644 tests/fixtures/parity/expected/extract__not_a_claim.json create mode 100644 tests/fixtures/parity/expected/extract__not_a_claim_beside_claims.json create mode 100644 tests/fixtures/parity/expected/extract__ready_one_claim.json create mode 100644 tests/fixtures/parity/expected/extract__ready_several_claims.json create mode 100644 tests/fixtures/parity/expected/extract__replay_later_200.json create mode 100644 tests/fixtures/parity/expected/extract__url_fetch_502_unreadable.json create mode 100644 tests/fixtures/parity/expected/extract__url_fetch_503_upstream.json create mode 100644 tests/fixtures/parity/expected/extract__url_input_located.json create mode 100644 tests/fixtures/parity/expected/review__401_no_credentials.json create mode 100644 tests/fixtures/parity/expected/review__402_no_credits.json create mode 100644 tests/fixtures/parity/expected/review__402_no_credits_exhausted.json create mode 100644 tests/fixtures/parity/expected/review__422_blank_text.json create mode 100644 tests/fixtures/parity/expected/review__422_citations_options_object.json create mode 100644 tests/fixtures/parity/expected/review__422_depth_unknown.json create mode 100644 tests/fixtures/parity/expected/review__422_invalid_confidence_band.json create mode 100644 tests/fixtures/parity/expected/review__422_invalid_verdict_label.json create mode 100644 tests/fixtures/parity/expected/review__422_max_assessments_negative.json create mode 100644 tests/fixtures/parity/expected/review__422_max_citations_negative.json create mode 100644 tests/fixtures/parity/expected/review__422_max_citations_too_big.json create mode 100644 tests/fixtures/parity/expected/review__422_max_verifications_too_big.json create mode 100644 tests/fixtures/parity/expected/review__422_text_missing.json create mode 100644 tests/fixtures/parity/expected/review__422_text_wrong_type.json create mode 100644 tests/fixtures/parity/expected/review__422_unknown_escalate_field.json create mode 100644 tests/fixtures/parity/expected/review__422_unknown_top_level_field.json create mode 100644 tests/fixtures/parity/expected/review__422_unsupported_language.json create mode 100644 tests/fixtures/parity/expected/review__422_visibility_public.json create mode 100644 tests/fixtures/parity/expected/review__429_extract_daily_limit.json create mode 100644 tests/fixtures/parity/expected/review__429_review_in_flight.json create mode 100644 tests/fixtures/parity/expected/review__503_capacity.json create mode 100644 tests/fixtures/parity/expected/review__503_citations_capacity.json create mode 100644 tests/fixtures/parity/expected/review__get_403_insufficient_scope.json create mode 100644 tests/fixtures/parity/expected/review__get_404_not_found.json create mode 100644 tests/fixtures/parity/expected/review__get_404_other_account.json create mode 100644 tests/fixtures/parity/expected/review__get_410_purged.json create mode 100644 tests/fixtures/parity/expected/review__get_422_unknown_view.json create mode 100644 tests/fixtures/parity/expected/review__get_assessing.json create mode 100644 tests/fixtures/parity/expected/review__get_assessment_rows_full_fields.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_clean.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_failed_and_unchecked.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_issue_full.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_issue_issues_view.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_limit_exactly_at_limit.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_limit_reached.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_no_claim_but_citations.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_no_claim_no_citation.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_not_asked.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_only.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_partly_supported.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_running.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_skipped_switched_off.json create mode 100644 tests/fixtures/parity/expected/review__get_citations_skipped_url_input.json create mode 100644 tests/fixtures/parity/expected/review__get_claim_limit_not_reached.json create mode 100644 tests/fixtures/parity/expected/review__get_claim_limit_reached_exact.json create mode 100644 tests/fixtures/parity/expected/review__get_completed_assess_only.json create mode 100644 tests/fixtures/parity/expected/review__get_completed_clean.json create mode 100644 tests/fixtures/parity/expected/review__get_completed_issues_all_verified.json create mode 100644 tests/fixtures/parity/expected/review__get_completed_issues_full.json create mode 100644 tests/fixtures/parity/expected/review__get_completed_issues_view_issues.json create mode 100644 tests/fixtures/parity/expected/review__get_completed_positions.json create mode 100644 tests/fixtures/parity/expected/review__get_completed_recovered_claim.json create mode 100644 tests/fixtures/parity/expected/review__get_completed_with_untraced_claim.json create mode 100644 tests/fixtures/parity/expected/review__get_during_quick_check.json create mode 100644 tests/fixtures/parity/expected/review__get_failed_every_assessment_failed.json create mode 100644 tests/fixtures/parity/expected/review__get_failed_no_claim.json create mode 100644 tests/fixtures/parity/expected/review__get_failed_no_claim_untraced.json create mode 100644 tests/fixtures/parity/expected/review__get_more_claims.json create mode 100644 tests/fixtures/parity/expected/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/expected/review__get_nested_verification_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/expected/review__get_policy_resolved.json create mode 100644 tests/fixtures/parity/expected/review__get_queued.json create mode 100644 tests/fixtures/parity/expected/review__get_suggested_edits.json create mode 100644 tests/fixtures/parity/expected/review__get_suggested_edits_issues_view.json create mode 100644 tests/fixtures/parity/expected/review__get_url_review.json create mode 100644 tests/fixtures/parity/expected/review__get_verifying.json create mode 100644 tests/fixtures/parity/expected/review__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/expected/review__idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/expected/review__idempotency_conflict_409_existing_review.json create mode 100644 tests/fixtures/parity/expected/review__idempotent_replay_202.json create mode 100644 tests/fixtures/parity/expected/review__receipt_202.json create mode 100644 tests/fixtures/parity/expected/review__receipt_202_empty_webhook_url.json create mode 100644 tests/fixtures/parity/expected/review__receipt_202_webhook_url.json create mode 100644 tests/fixtures/parity/expected/review__replay_later_202.json create mode 100644 tests/fixtures/parity/expected/verify__batch_202.json create mode 100644 tests/fixtures/parity/expected/verify__batch_capacity_503.json create mode 100644 tests/fixtures/parity/expected/verify__batch_empty_422.json create mode 100644 tests/fixtures/parity/expected/verify__batch_idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/expected/verify__batch_item_missing_claim_422.json create mode 100644 tests/fixtures/parity/expected/verify__batch_no_credits_402.json create mode 100644 tests/fixtures/parity/expected/verify__batch_partial_202.json create mode 100644 tests/fixtures/parity/expected/verify__batch_too_many_422.json create mode 100644 tests/fixtures/parity/expected/verify__blank_claim_422.json create mode 100644 tests/fixtures/parity/expected/verify__capacity_503.json create mode 100644 tests/fixtures/parity/expected/verify__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/expected/verify__idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/expected/verify__idempotency_key_replay.json create mode 100644 tests/fixtures/parity/expected/verify__implicit_dedup_200.json create mode 100644 tests/fixtures/parity/expected/verify__implicit_repeat_replay.json create mode 100644 tests/fixtures/parity/expected/verify__invalid_depth_422.json create mode 100644 tests/fixtures/parity/expected/verify__invalid_language_422.json create mode 100644 tests/fixtures/parity/expected/verify__list_200.json create mode 100644 tests/fixtures/parity/expected/verify__list_200_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/expected/verify__list_200_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/expected/verify__list_clamped_200.json create mode 100644 tests/fixtures/parity/expected/verify__list_empty_200.json create mode 100644 tests/fixtures/parity/expected/verify__list_page2_200.json create mode 100644 tests/fixtures/parity/expected/verify__misnamed_field_422.json create mode 100644 tests/fixtures/parity/expected/verify__missing_claim_422.json create mode 100644 tests/fixtures/parity/expected/verify__no_credits_402.json create mode 100644 tests/fixtures/parity/expected/verify__replay_later_202.json create mode 100644 tests/fixtures/parity/expected/verify__select_202.json create mode 100644 tests/fixtures/parity/expected/verify__select_empty_422.json create mode 100644 tests/fixtures/parity/expected/verify__select_invalid_selection_422.json create mode 100644 tests/fixtures/parity/expected/verify__select_no_selection_pending_409.json create mode 100644 tests/fixtures/parity/expected/verify__select_too_many_422.json create mode 100644 tests/fixtures/parity/expected/verify__select_unknown_task_404.json create mode 100644 tests/fixtures/parity/expected/verify__status_cancelled_after_a_while.json create mode 100644 tests/fixtures/parity/expected/verify__status_completed.json create mode 100644 tests/fixtures/parity/expected/verify__status_completed_after_a_while.json create mode 100644 tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/expected/verify__status_completed_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/expected/verify__status_completed_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/expected/verify__status_failed.json create mode 100644 tests/fixtures/parity/expected/verify__status_failed_after_a_while.json create mode 100644 tests/fixtures/parity/expected/verify__status_failed_after_a_while_framing.json create mode 100644 tests/fixtures/parity/expected/verify__status_failed_retryable.json create mode 100644 tests/fixtures/parity/expected/verify__status_needs_input.json create mode 100644 tests/fixtures/parity/expected/verify__status_not_a_claim.json create mode 100644 tests/fixtures/parity/expected/verify__status_not_a_claim_after_a_while.json create mode 100644 tests/fixtures/parity/expected/verify__status_not_yours_404.json create mode 100644 tests/fixtures/parity/expected/verify__status_older_run_completed.json create mode 100644 tests/fixtures/parity/expected/verify__status_older_run_failed_crashed.json create mode 100644 tests/fixtures/parity/expected/verify__status_older_run_failed_insufficient_evidence.json create mode 100644 tests/fixtures/parity/expected/verify__status_older_run_in_progress.json create mode 100644 tests/fixtures/parity/expected/verify__status_processing.json create mode 100644 tests/fixtures/parity/expected/verify__status_processing_after_a_while.json create mode 100644 tests/fixtures/parity/expected/verify__status_task_stuck.json create mode 100644 tests/fixtures/parity/expected/verify__status_unknown_404.json create mode 100644 tests/fixtures/parity/expected/verify__submit_202.json create mode 100644 tests/fixtures/parity/expected/verify__submit_202_options.json create mode 100644 tests/fixtures/parity/expected/verify__submit_202_text_alias.json create mode 100644 tests/fixtures/parity/expected/verify__unauthenticated_401.json create mode 100644 tests/fixtures/parity/expected/verify__verification_200.json create mode 100644 tests/fixtures/parity/expected/verify__verification_200_covered.json create mode 100644 tests/fixtures/parity/expected/verify__verification_200_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/expected/verify__verification_200_modified_at_null.json create mode 100644 tests/fixtures/parity/expected/verify__verification_200_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/expected/verify__verification_200_modified_at_set.json create mode 100644 tests/fixtures/parity/expected/verify__verification_200_result_json_conclusion_only.json create mode 100644 tests/fixtures/parity/expected/verify__verification_200_result_json_empty.json create mode 100644 tests/fixtures/parity/expected/verify__verification_200_result_json_old_shape_strings.json create mode 100644 tests/fixtures/parity/expected/verify__verification_404.json create mode 100644 tests/fixtures/parity/expected/verify__verification_by_task_id_200.json create mode 100644 tests/fixtures/parity/expected/verify__verification_failed_409.json create mode 100644 tests/fixtures/parity/expected/verify__verification_failed_409_not_a_claim_after_a_while.json create mode 100644 tests/fixtures/parity/expected/verify__verification_not_ready_409.json create mode 100644 tests/fixtures/parity/expected/verify__verification_not_yours_404.json create mode 100644 tests/fixtures/parity/expected/verify__verification_public_anonymous.json create mode 100644 tests/fixtures/parity/expected/verify__verification_public_of_another_user.json create mode 100644 tests/fixtures/parity/expected/verify__verification_unknown_task_404.json create mode 100644 tests/fixtures/parity/expected/verify__verification_zero_retention_expired_410.json create mode 100644 tests/fixtures/parity/expected/verify__verification_zero_retention_served.json create mode 100644 tests/fixtures/parity/expected/webhook__certificate_timestamped.json create mode 100644 tests/fixtures/parity/expected/webhook__certificate_timestamped_review_child.json create mode 100644 tests/fixtures/parity/expected/webhook__citecheck_completed.json create mode 100644 tests/fixtures/parity/expected/webhook__citecheck_failed.json create mode 100644 tests/fixtures/parity/expected/webhook__review_completed.json create mode 100644 tests/fixtures/parity/expected/webhook__review_completed_key_default_url.json create mode 100644 tests/fixtures/parity/expected/webhook__review_completed_oversized_rebuilt.json create mode 100644 tests/fixtures/parity/expected/webhook__review_failed.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_completed.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_completed_in_batch.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_completed_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_failed_insufficient_evidence.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_failed_not_a_claim.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_failed_upstream_unavailable.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_needs_input_multi_claim.json create mode 100644 tests/fixtures/parity/legacy/account__library_empty.json create mode 100644 tests/fixtures/parity/legacy/account__library_item_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/legacy/account__library_item_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/legacy/account__library_items.json create mode 100644 tests/fixtures/parity/legacy/account__library_no_match.json create mode 100644 tests/fixtures/parity/legacy/account__library_page_past_end.json create mode 100644 tests/fixtures/parity/legacy/account__library_paginated_second_page.json create mode 100644 tests/fixtures/parity/legacy/account__me_usage_extra_credits.json create mode 100644 tests/fixtures/parity/legacy/account__me_usage_extra_only.json create mode 100644 tests/fixtures/parity/legacy/account__me_usage_extract_calls.json create mode 100644 tests/fixtures/parity/legacy/account__me_usage_free.json create mode 100644 tests/fixtures/parity/legacy/account__me_usage_free_partly_spent.json create mode 100644 tests/fixtures/parity/legacy/account__me_usage_plus.json create mode 100644 tests/fixtures/parity/legacy/account__me_usage_pro.json create mode 100644 tests/fixtures/parity/legacy/account__me_usage_pro_extra.json create mode 100644 tests/fixtures/parity/legacy/account__me_usage_stale_quota_row.json create mode 100644 tests/fixtures/parity/legacy/assess__401_no_key.json create mode 100644 tests/fixtures/parity/legacy/assess__402_no_credits.json create mode 100644 tests/fixtures/parity/legacy/assess__422_blank_item.json create mode 100644 tests/fixtures/parity/legacy/assess__422_blank_text.json create mode 100644 tests/fixtures/parity/legacy/assess__422_input_conflict.json create mode 100644 tests/fixtures/parity/legacy/assess__422_item_too_long.json create mode 100644 tests/fixtures/parity/legacy/assess__422_no_input_field.json create mode 100644 tests/fixtures/parity/legacy/assess__422_too_many_items.json create mode 100644 tests/fixtures/parity/legacy/assess__422_wrong_type_claim.json create mode 100644 tests/fixtures/parity/legacy/assess__422_wrong_type_claims.json create mode 100644 tests/fixtures/parity/legacy/assess__502_framing_failed.json create mode 100644 tests/fixtures/parity/legacy/assess__503_capacity.json create mode 100644 tests/fixtures/parity/legacy/assess__503_list_all_upstream_unavailable.json create mode 100644 tests/fixtures/parity/legacy/assess__503_upstream_unavailable.json create mode 100644 tests/fixtures/parity/legacy/assess__deep_tier_hit.json create mode 100644 tests/fixtures/parity/legacy/assess__idempotency_body_mismatch.json create mode 100644 tests/fixtures/parity/legacy/assess__idempotency_first.json create mode 100644 tests/fixtures/parity/legacy/assess__idempotency_replay.json create mode 100644 tests/fixtures/parity/legacy/assess__list_all_error_rows.json create mode 100644 tests/fixtures/parity/legacy/assess__list_compound_item.json create mode 100644 tests/fixtures/parity/legacy/assess__list_mixed_rows.json create mode 100644 tests/fixtures/parity/legacy/assess__memo_hit.json create mode 100644 tests/fixtures/parity/legacy/assess__replay_later_200.json create mode 100644 tests/fixtures/parity/legacy/assess__single_no_claim.json create mode 100644 tests/fixtures/parity/legacy/assess__single_one_claim.json create mode 100644 tests/fixtures/parity/legacy/assess__single_text_over_wave_more_claims.json create mode 100644 tests/fixtures/parity/legacy/assess__single_text_several_claims.json create mode 100644 tests/fixtures/parity/legacy/assess__suggest_rewrite.json create mode 100644 tests/fixtures/parity/legacy/citecheck__402_no_credits.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_empty_body.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_invalid_doi.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_max_citations_over_20.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_max_citations_with_pairs.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_pair_bad_url_scheme.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_pair_no_source.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_pair_url_and_doi.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_pairs_empty.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_pairs_over_20.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_quote_not_in_statement.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_text_and_pairs.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_unknown_field.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_url_input.json create mode 100644 tests/fixtures/parity/legacy/citecheck__429_citecheck_in_flight.json create mode 100644 tests/fixtures/parity/legacy/citecheck__503_capacity.json create mode 100644 tests/fixtures/parity/legacy/citecheck__503_citations_unavailable.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_404_not_found.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_404_review_id.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_410_purged.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_checking.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_completed_clean.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_completed_doi_pair.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_completed_incomplete.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_completed_issues_found.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_completed_partly_supported.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_completed_unchecked.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_failed_no_citations.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_failed_upstream_unavailable.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_queued.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_text_limit_exactly_at_limit.json create mode 100644 tests/fixtures/parity/legacy/citecheck__get_text_limit_reached.json create mode 100644 tests/fixtures/parity/legacy/citecheck__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/legacy/citecheck__idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/legacy/citecheck__idempotent_replay_202.json create mode 100644 tests/fixtures/parity/legacy/citecheck__receipt_202.json create mode 100644 tests/fixtures/parity/legacy/citecheck__receipt_202_empty_webhook_url.json create mode 100644 tests/fixtures/parity/legacy/errors__ask_bad_language.json create mode 100644 tests/fixtures/parity/legacy/errors__ask_empty_message.json create mode 100644 tests/fixtures/parity/legacy/errors__ask_failed.json create mode 100644 tests/fixtures/parity/legacy/errors__ask_idempotency_key_reused.json create mode 100644 tests/fixtures/parity/legacy/errors__ask_message_too_long.json create mode 100644 tests/fixtures/parity/legacy/errors__ask_not_completed.json create mode 100644 tests/fixtures/parity/legacy/errors__ask_reset_not_found.json create mode 100644 tests/fixtures/parity/legacy/errors__ask_send_not_found.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_bad_key.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_basic_scheme.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_insufficient_scope.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_missing_bearer.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_missing_bearer_post.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_private_claim_ask_history.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_private_claim_ask_send.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_unrecognised_prefix.json create mode 100644 tests/fixtures/parity/legacy/errors__http_error_library_bad_curated.json create mode 100644 tests/fixtures/parity/legacy/errors__http_error_library_bad_verdict.json create mode 100644 tests/fixtures/parity/legacy/errors__not_found_ask.json create mode 100644 tests/fixtures/parity/legacy/errors__not_found_route.json create mode 100644 tests/fixtures/parity/legacy/errors__not_found_verification.json create mode 100644 tests/fixtures/parity/legacy/errors__not_found_verify_status.json create mode 100644 tests/fixtures/parity/legacy/errors__payment_required_ask.json create mode 100644 tests/fixtures/parity/legacy/errors__payment_required_assess.json create mode 100644 tests/fixtures/parity/legacy/errors__payment_required_verify.json create mode 100644 tests/fixtures/parity/legacy/errors__payment_required_verify_batch_short.json create mode 100644 tests/fixtures/parity/legacy/errors__rate_limited_extract.json create mode 100644 tests/fixtures/parity/legacy/errors__service_unavailable_ask.json create mode 100644 tests/fixtures/parity/legacy/errors__service_unavailable_capacity.json create mode 100644 tests/fixtures/parity/legacy/errors__validation_malformed_json.json create mode 100644 tests/fixtures/parity/legacy/errors__validation_missing_field_hint.json create mode 100644 tests/fixtures/parity/legacy/errors__validation_unknown_field_only.json create mode 100644 tests/fixtures/parity/legacy/errors__validation_unknown_field_wrong_type.json create mode 100644 tests/fixtures/parity/legacy/errors__validation_wrong_type.json create mode 100644 tests/fixtures/parity/legacy/extract__401_no_key.json create mode 100644 tests/fixtures/parity/legacy/extract__422_blank_text.json create mode 100644 tests/fixtures/parity/legacy/extract__422_focus_too_long.json create mode 100644 tests/fixtures/parity/legacy/extract__422_missing_text.json create mode 100644 tests/fixtures/parity/legacy/extract__429_daily_limit.json create mode 100644 tests/fixtures/parity/legacy/extract__502_extraction_failed.json create mode 100644 tests/fixtures/parity/legacy/extract__503_upstream_unavailable.json create mode 100644 tests/fixtures/parity/legacy/extract__focus_ready.json create mode 100644 tests/fixtures/parity/legacy/extract__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/legacy/extract__idempotency_replay.json create mode 100644 tests/fixtures/parity/legacy/extract__locate_all_dropped.json create mode 100644 tests/fixtures/parity/legacy/extract__locate_failed.json create mode 100644 tests/fixtures/parity/legacy/extract__locate_leading_whitespace.json create mode 100644 tests/fixtures/parity/legacy/extract__locate_some_dropped.json create mode 100644 tests/fixtures/parity/legacy/extract__locate_true.json create mode 100644 tests/fixtures/parity/legacy/extract__no_match_with_focus.json create mode 100644 tests/fixtures/parity/legacy/extract__not_a_claim.json create mode 100644 tests/fixtures/parity/legacy/extract__not_a_claim_beside_claims.json create mode 100644 tests/fixtures/parity/legacy/extract__ready_one_claim.json create mode 100644 tests/fixtures/parity/legacy/extract__ready_several_claims.json create mode 100644 tests/fixtures/parity/legacy/extract__replay_later_200.json create mode 100644 tests/fixtures/parity/legacy/extract__url_fetch_502_unreadable.json create mode 100644 tests/fixtures/parity/legacy/extract__url_fetch_503_upstream.json create mode 100644 tests/fixtures/parity/legacy/extract__url_input_located.json create mode 100644 tests/fixtures/parity/legacy/review__401_no_credentials.json create mode 100644 tests/fixtures/parity/legacy/review__402_no_credits.json create mode 100644 tests/fixtures/parity/legacy/review__402_no_credits_exhausted.json create mode 100644 tests/fixtures/parity/legacy/review__422_blank_text.json create mode 100644 tests/fixtures/parity/legacy/review__422_citations_options_object.json create mode 100644 tests/fixtures/parity/legacy/review__422_depth_unknown.json create mode 100644 tests/fixtures/parity/legacy/review__422_invalid_confidence_band.json create mode 100644 tests/fixtures/parity/legacy/review__422_invalid_verdict_label.json create mode 100644 tests/fixtures/parity/legacy/review__422_max_assessments_negative.json create mode 100644 tests/fixtures/parity/legacy/review__422_max_citations_negative.json create mode 100644 tests/fixtures/parity/legacy/review__422_max_citations_too_big.json create mode 100644 tests/fixtures/parity/legacy/review__422_max_verifications_too_big.json create mode 100644 tests/fixtures/parity/legacy/review__422_text_missing.json create mode 100644 tests/fixtures/parity/legacy/review__422_text_wrong_type.json create mode 100644 tests/fixtures/parity/legacy/review__422_unknown_escalate_field.json create mode 100644 tests/fixtures/parity/legacy/review__422_unknown_top_level_field.json create mode 100644 tests/fixtures/parity/legacy/review__422_unsupported_language.json create mode 100644 tests/fixtures/parity/legacy/review__422_visibility_public.json create mode 100644 tests/fixtures/parity/legacy/review__429_extract_daily_limit.json create mode 100644 tests/fixtures/parity/legacy/review__429_review_in_flight.json create mode 100644 tests/fixtures/parity/legacy/review__503_capacity.json create mode 100644 tests/fixtures/parity/legacy/review__503_citations_capacity.json create mode 100644 tests/fixtures/parity/legacy/review__get_403_insufficient_scope.json create mode 100644 tests/fixtures/parity/legacy/review__get_404_not_found.json create mode 100644 tests/fixtures/parity/legacy/review__get_404_other_account.json create mode 100644 tests/fixtures/parity/legacy/review__get_410_purged.json create mode 100644 tests/fixtures/parity/legacy/review__get_422_unknown_view.json create mode 100644 tests/fixtures/parity/legacy/review__get_assessing.json create mode 100644 tests/fixtures/parity/legacy/review__get_assessment_rows_full_fields.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_clean.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_failed_and_unchecked.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_issue_full.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_issue_issues_view.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_limit_exactly_at_limit.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_limit_reached.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_no_claim_but_citations.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_no_claim_no_citation.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_not_asked.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_only.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_partly_supported.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_running.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_skipped_switched_off.json create mode 100644 tests/fixtures/parity/legacy/review__get_citations_skipped_url_input.json create mode 100644 tests/fixtures/parity/legacy/review__get_claim_limit_not_reached.json create mode 100644 tests/fixtures/parity/legacy/review__get_claim_limit_reached_exact.json create mode 100644 tests/fixtures/parity/legacy/review__get_completed_assess_only.json create mode 100644 tests/fixtures/parity/legacy/review__get_completed_clean.json create mode 100644 tests/fixtures/parity/legacy/review__get_completed_issues_all_verified.json create mode 100644 tests/fixtures/parity/legacy/review__get_completed_issues_full.json create mode 100644 tests/fixtures/parity/legacy/review__get_completed_issues_view_issues.json create mode 100644 tests/fixtures/parity/legacy/review__get_completed_positions.json create mode 100644 tests/fixtures/parity/legacy/review__get_completed_recovered_claim.json create mode 100644 tests/fixtures/parity/legacy/review__get_completed_with_untraced_claim.json create mode 100644 tests/fixtures/parity/legacy/review__get_during_quick_check.json create mode 100644 tests/fixtures/parity/legacy/review__get_failed_every_assessment_failed.json create mode 100644 tests/fixtures/parity/legacy/review__get_failed_no_claim.json create mode 100644 tests/fixtures/parity/legacy/review__get_failed_no_claim_untraced.json create mode 100644 tests/fixtures/parity/legacy/review__get_more_claims.json create mode 100644 tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/legacy/review__get_policy_resolved.json create mode 100644 tests/fixtures/parity/legacy/review__get_queued.json create mode 100644 tests/fixtures/parity/legacy/review__get_suggested_edits.json create mode 100644 tests/fixtures/parity/legacy/review__get_suggested_edits_issues_view.json create mode 100644 tests/fixtures/parity/legacy/review__get_url_review.json create mode 100644 tests/fixtures/parity/legacy/review__get_verifying.json create mode 100644 tests/fixtures/parity/legacy/review__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/legacy/review__idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/legacy/review__idempotency_conflict_409_existing_review.json create mode 100644 tests/fixtures/parity/legacy/review__idempotent_replay_202.json create mode 100644 tests/fixtures/parity/legacy/review__receipt_202.json create mode 100644 tests/fixtures/parity/legacy/review__receipt_202_empty_webhook_url.json create mode 100644 tests/fixtures/parity/legacy/review__receipt_202_webhook_url.json create mode 100644 tests/fixtures/parity/legacy/review__replay_later_202.json create mode 100644 tests/fixtures/parity/legacy/verify__batch_202.json create mode 100644 tests/fixtures/parity/legacy/verify__batch_capacity_503.json create mode 100644 tests/fixtures/parity/legacy/verify__batch_empty_422.json create mode 100644 tests/fixtures/parity/legacy/verify__batch_idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/legacy/verify__batch_item_missing_claim_422.json create mode 100644 tests/fixtures/parity/legacy/verify__batch_no_credits_402.json create mode 100644 tests/fixtures/parity/legacy/verify__batch_partial_202.json create mode 100644 tests/fixtures/parity/legacy/verify__batch_too_many_422.json create mode 100644 tests/fixtures/parity/legacy/verify__blank_claim_422.json create mode 100644 tests/fixtures/parity/legacy/verify__capacity_503.json create mode 100644 tests/fixtures/parity/legacy/verify__idempotency_body_mismatch_422.json create mode 100644 tests/fixtures/parity/legacy/verify__idempotency_conflict_409.json create mode 100644 tests/fixtures/parity/legacy/verify__idempotency_key_replay.json create mode 100644 tests/fixtures/parity/legacy/verify__implicit_dedup_200.json create mode 100644 tests/fixtures/parity/legacy/verify__implicit_repeat_replay.json create mode 100644 tests/fixtures/parity/legacy/verify__invalid_depth_422.json create mode 100644 tests/fixtures/parity/legacy/verify__invalid_language_422.json create mode 100644 tests/fixtures/parity/legacy/verify__list_200.json create mode 100644 tests/fixtures/parity/legacy/verify__list_200_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/legacy/verify__list_200_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/legacy/verify__list_clamped_200.json create mode 100644 tests/fixtures/parity/legacy/verify__list_empty_200.json create mode 100644 tests/fixtures/parity/legacy/verify__list_page2_200.json create mode 100644 tests/fixtures/parity/legacy/verify__misnamed_field_422.json create mode 100644 tests/fixtures/parity/legacy/verify__missing_claim_422.json create mode 100644 tests/fixtures/parity/legacy/verify__no_credits_402.json create mode 100644 tests/fixtures/parity/legacy/verify__replay_later_202.json create mode 100644 tests/fixtures/parity/legacy/verify__select_202.json create mode 100644 tests/fixtures/parity/legacy/verify__select_empty_422.json create mode 100644 tests/fixtures/parity/legacy/verify__select_invalid_selection_422.json create mode 100644 tests/fixtures/parity/legacy/verify__select_no_selection_pending_409.json create mode 100644 tests/fixtures/parity/legacy/verify__select_too_many_422.json create mode 100644 tests/fixtures/parity/legacy/verify__select_unknown_task_404.json create mode 100644 tests/fixtures/parity/legacy/verify__status_cancelled_after_a_while.json create mode 100644 tests/fixtures/parity/legacy/verify__status_completed.json create mode 100644 tests/fixtures/parity/legacy/verify__status_completed_after_a_while.json create mode 100644 tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/legacy/verify__status_completed_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/legacy/verify__status_completed_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/legacy/verify__status_failed.json create mode 100644 tests/fixtures/parity/legacy/verify__status_failed_after_a_while.json create mode 100644 tests/fixtures/parity/legacy/verify__status_failed_after_a_while_framing.json create mode 100644 tests/fixtures/parity/legacy/verify__status_failed_retryable.json create mode 100644 tests/fixtures/parity/legacy/verify__status_needs_input.json create mode 100644 tests/fixtures/parity/legacy/verify__status_not_a_claim.json create mode 100644 tests/fixtures/parity/legacy/verify__status_not_a_claim_after_a_while.json create mode 100644 tests/fixtures/parity/legacy/verify__status_not_yours_404.json create mode 100644 tests/fixtures/parity/legacy/verify__status_older_run_completed.json create mode 100644 tests/fixtures/parity/legacy/verify__status_older_run_failed_crashed.json create mode 100644 tests/fixtures/parity/legacy/verify__status_older_run_failed_insufficient_evidence.json create mode 100644 tests/fixtures/parity/legacy/verify__status_older_run_in_progress.json create mode 100644 tests/fixtures/parity/legacy/verify__status_processing.json create mode 100644 tests/fixtures/parity/legacy/verify__status_processing_after_a_while.json create mode 100644 tests/fixtures/parity/legacy/verify__status_task_stuck.json create mode 100644 tests/fixtures/parity/legacy/verify__status_unknown_404.json create mode 100644 tests/fixtures/parity/legacy/verify__submit_202.json create mode 100644 tests/fixtures/parity/legacy/verify__submit_202_options.json create mode 100644 tests/fixtures/parity/legacy/verify__submit_202_text_alias.json create mode 100644 tests/fixtures/parity/legacy/verify__unauthenticated_401.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_200.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_200_covered.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_200_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_200_modified_at_null.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_200_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_200_modified_at_set.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_200_result_json_conclusion_only.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_200_result_json_empty.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_200_result_json_old_shape_strings.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_404.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_by_task_id_200.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_failed_409.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_failed_409_not_a_claim_after_a_while.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_not_ready_409.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_not_yours_404.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_public_anonymous.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_public_of_another_user.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_unknown_task_404.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_zero_retention_expired_410.json create mode 100644 tests/fixtures/parity/legacy/verify__verification_zero_retention_served.json create mode 100644 tests/fixtures/parity/legacy/webhook__certificate_timestamped.json create mode 100644 tests/fixtures/parity/legacy/webhook__certificate_timestamped_review_child.json create mode 100644 tests/fixtures/parity/legacy/webhook__citecheck_completed.json create mode 100644 tests/fixtures/parity/legacy/webhook__citecheck_failed.json create mode 100644 tests/fixtures/parity/legacy/webhook__review_completed.json create mode 100644 tests/fixtures/parity/legacy/webhook__review_completed_key_default_url.json create mode 100644 tests/fixtures/parity/legacy/webhook__review_completed_oversized_rebuilt.json create mode 100644 tests/fixtures/parity/legacy/webhook__review_failed.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_completed.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_completed_in_batch.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_same_day_hours_apart.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_failed_insufficient_evidence.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_failed_not_a_claim.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_failed_upstream_unavailable.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_needs_input_multi_claim.json create mode 100644 tests/fixtures/parity/requests.json create mode 100644 tests/parity_generate.py create mode 100644 tests/parity_observe.py create mode 100644 tests/parity_requests.py create mode 100644 tests/test_parity.py create mode 100644 tests/test_read_both_shapes.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 058d2e9..17abab8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,82 @@ All notable changes to this SDK are documented here. Format follows ## [Unreleased] +Minor release (2.21.0). Existing code keeps working unchanged; nothing to do +on upgrade. + +### Added + +- **Reads both response shapes.** The API is adding a newer, dated response + shape that gives each field one name across every endpoint. This release + still asks for the original shape (it sends the same `X-Lenz-API-Version` + as before), and every model now reads either shape. The newer names are + attributes now, filled from whichever shape arrives: + - `ExtractedClaims.claims`: every claim found, always a list, each an + `ExtractedClaim` with `claim` and (with `locate=True`) `positions`. + - `AssessClaim.status` (`"completed"` / `"failed"`), `AssessClaim.failure` + (`code`, `detail`, `hint`, `failure_class`, `retryable`, `docs_url`) and + `AssessClaim.more_claims`; `AssessResponse.status` (`ok` / + `no_checkable_claim` / `error`, the `AssessStatus` constant) and + `AssessResponse.failure`. + - `TaskStatus.failure`, the same block, on a failed verification. + - `TaskAccepted.claim`, `BatchItemResult.claim`, `CandidateClaim.claim`. + - `completed_at` on `Verification`, `VerificationListItem` and + `ReviewVerification`. + - `FailureBlock.code` and `FailureBlock.detail`; + `ReviewAssessment.more_claims`; `ReviewSummary.claims_found`, + `claim_limit_exceeded` and `citation_limit_exceeded`; + `CitecheckSummary.citation_limit_exceeded`. + - Webhooks: `event_id` on every event, `VerificationFailed.failure`, + `VerificationNeedsInput.reason` and `.claims`. `parse_webhook` and + `LenzWebhooks.parse` read the newer envelope too (`event`, `event_id`, + the work's id, `status`, and the polled body under `verification` / + `review` / `citecheck`). + - Errors: a 409 for a failed run, a 429 and a 422 are read in either shape + (`failure` block, `retry_after`, `errors` list with a sentence `detail`). + +### Deprecated + +- The older names, kept with the meaning they always had, whichever shape + arrives: `ExtractedClaims.claim` / `identified_claims` / `locations`; + `AssessClaim.error_code` / `hint` / `identified_claims` (a failed row still + reads `verdict == "Error"` and `confidence == "low"`); `AssessResponse.error` + / `error_code`; `TaskStatus.error` / `failure_reason` / `failure_detail`; + `claim_text` and `CandidateClaim.text`; `modified_at` (computed from + `completed_at` with its original rule: set only when the verification + completed on a later UTC calendar day than it was created); + `FailureBlock.failure_reason`; `ReviewAssessment.error_code` / `hint` / + `identified_claims`; `claim_limit_reached` / `citation_limit_reached`; + `Usage.quota_resets_at` and the `verify` / `ask` / `assess` blocks (computed + from `credits` and `costs` when a response leaves them out). They are marked + deprecated in the JSON schema; reading them does not warn. "Nothing + checkable" keeps its old spelling in the old fields (`not_a_claim`, + `no_claim`) and reads `no_checkable_claim` in the new ones; + `ExtractedClaims.status` keeps `not_a_claim`. + +### Changed + +- **`verify`, `verify_and_wait`, `verify_batch` and `verify_batch_and_wait` + no longer send `webhook_url: ""`** when no webhook URL was given (nor an + empty per-item `webhook_url`). The API has always read an empty value there + as "use the key's default webhook", the same as leaving it out, so nothing + changes now; leaving it out keeps that meaning on later API versions, where + `""` means "no webhook". A retry that reuses an idempotency key from an + earlier release's call sends a different body and is refused as a + different request. `review` and `citecheck` send `webhook_url` exactly as + before (there `""` means "no webhook"). +- `model_dump()` returns the shape the server sent: attributes filled in from + the other shape are left out, so an original-shape response dumps exactly as + before. + +### Correction + +- **The /me/usage fields are not removed on 2026-11-29.** Earlier entries + (2.9.0 and 2.14.0) said `UsageCredits.bonus`, `UsageCapacity.credits` and the + per-capability `verify` / `ask` / `assess` blocks would go on that date. + They are deprecated and kept for existing callers; the API keeps sending + them to integrations built against its original shape. Their deprecation + warnings no longer name a date. + ## [2.20.0] - 2026-10-05 ### Added diff --git a/README.md b/README.md index efc0025..502a192 100644 --- a/README.md +++ b/README.md @@ -221,7 +221,7 @@ edited = "".join(chars) `poll_after_seconds`. Pass `on_update=` to see the quick verdicts as soon as they are in and each deep check as it lands; without it the helper is silent. It raises `ReviewFailed` when the review fails (`error_code` and `hint` say -why) and `ReviewTimeout` after `timeout` seconds (600 by default); the review +why; `review.failure.code` is the cause in the newer spelling) and `ReviewTimeout` after `timeout` seconds (600 by default); the review keeps running, and the error carries its `review_id` and the last body read. To submit without waiting, `client.review(draft)` returns a `review_id`; read it with `client.get_review(review_id)`, or only the issues with @@ -297,7 +297,7 @@ client = Lenz(api_key="lenz_...") # 1. extract — pull verifiable claims out of any text (free) # add focus="..." to narrow it to the claims you care about out = client.extract(text=llm_output) -claims = out.identified_claims or [out.claim] +claims = [c.claim for c in out.claims] # 2. assess — one call per 20 claims (extract finds up to 100), one row per claim, same order quick = [row for i in range(0, len(claims), 20) for row in client.assess(claims=claims[i : i + 20]).claims] @@ -308,7 +308,7 @@ for c in quick: # 3. verify — escalate the low-confidence rows to the full panel + citations # verify_batch_and_wait takes up to 20 claims a call: the first 20 here -doubtful = [{"claim": c.claim} for c in quick if c.verdict != "Error" and c.confidence == "low"][:20] +doubtful = [{"claim": c.claim} for c in quick if c.status == "completed" and c.confidence == "low"][:20] results = client.verify_batch_and_wait(claims=doubtful) if doubtful else [] for r in results: if r.verification: @@ -322,13 +322,13 @@ print(reply.content) `assess(claims=[...])` takes up to 20 claims per call and always answers with exactly one row per claim, in the order sent. A row that could not be -given a verdict comes back in position with `verdict == "Error"`, an -`error_code` (`no_claim` / `framing_failed` / `upstream_unavailable` / -`timeout` — an open set; the last two are the ones worth resending as-is) -and a one-sentence `hint` on what to send next; it is not charged. A -compound item is assessed on its main claim and lists the other claims it -found in `identified_claims` (also with a `hint`) — send those as their own -items to check the rest. `assess(claim="...")` takes one text and answers +given a verdict comes back in position with `status == "failed"` and a +`failure` block: `failure.code` (`no_checkable_claim` / `framing_failed` / +`upstream_unavailable` / `timeout` — an open set; the last two are the ones +worth resending as-is) and `failure.hint`, one sentence on what to send next; +it is not charged. A compound item is assessed on its main claim and lists the +other claims it found in `more_claims` — send those as their own items to +check the rest. `assess(claim="...")` takes one text and answers with a row per claim found in it, up to 20, at 1 credit each; a text that makes more claims gets its 20 most check-worthy checked and the rest in `more_claims`, unchecked and free — send them back as `claims`, 20 a call. @@ -387,8 +387,8 @@ your own claims. Use webhooks for production async flows. ## What you get on the client -- **`client.extract(text=...)`** → `ExtractedClaims`. Free, capped at 1000/account/day. Add `focus=` to narrow the list — see [Steering extract](#steering-extract) — and `locate=True` to keep only the claims traced back to your text, with their positions (`out.locations`). Each attempt waits up to 150s by default (a timeout is retried like any transport error, and the call's idempotency key makes the retry replay the first answer); `timeout=` overrides it for that call. -- **`client.assess(claim=...)`** / **`client.assess(claims=[...])`** → `AssessResponse`. Sync. One statement (~15s; `text=` is accepted as an alias: a document is `text`, a claim is `claim`) or a list of up to 20 claims in one call (~15s) — exactly one row per claim, in order; rows that got no verdict are `"Error"` rows with an `error_code` and a `hint`, in position and free. A single text past 20 claims lists the rest in `more_claims` (`[]` otherwise). The two forms are mutually exclusive. `timeout=` overrides the client timeout for that call (both forms default to 100s: a long text can take up to 90s). +- **`client.extract(text=...)`** → `ExtractedClaims`. Free, capped at 1000/account/day. Add `focus=` to narrow the list — see [Steering extract](#steering-extract) — and `locate=True` to keep only the claims traced back to your text, with their positions (each `out.claims[i].positions`). Each attempt waits up to 150s by default (a timeout is retried like any transport error, and the call's idempotency key makes the retry replay the first answer); `timeout=` overrides it for that call. +- **`client.assess(claim=...)`** / **`client.assess(claims=[...])`** → `AssessResponse`. Sync. One statement (~15s; `text=` is accepted as an alias: a document is `text`, a claim is `claim`) or a list of up to 20 claims in one call (~15s) — exactly one row per claim, in order; rows that got no verdict have `status == "failed"` and a `failure` block (`failure.code`, `failure.hint`), in position and free. A single text past 20 claims lists the rest in `more_claims` (`[]` otherwise). The two forms are mutually exclusive. `timeout=` overrides the client timeout for that call (both forms default to 100s: a long text can take up to 90s). - **`client.verify(...)`** → `TaskAccepted`. Async submit; returns a `task_id`. Get the result by polling (`client.wait(...)` / `client.get_status(...)`) or via a webhook. - **`client.verify_and_wait(...)`** → `Verification`. Submit + poll until the pipeline lands (sync ergonomic). Equivalent to `wait(verify(...))`. - **`client.wait(task)`** → `Verification`. Block on a `task_id` (or a `TaskAccepted`) until it terminates. The polling counterpart to a webhook. @@ -426,9 +426,9 @@ results = client.verify_batch_and_wait( ) for r in results: if r.status == "completed": - print(r.claim_text, "→", r.verification.verdict) + print(r.claim, "→", r.verification.verdict) else: - print(r.claim_text, "→", r.status) # needs_input | failed | timeout + print(r.claim, "→", r.status) # needs_input | failed | timeout ``` A `failed` item with `status_detail is None` is a verification its account's @@ -471,6 +471,30 @@ Every claim-shaped response shares these fields at top level: | `confidence` | `str` | Categorical: `"high"` \| `"medium"` \| `"low"`. | | `lenz_score` | `int \| None` | Integer 1–10 (deep verdicts and list endpoints; `assess` omits it). | +### Field names: both response shapes + +The API is adding a newer, dated response shape that gives each field one +name across every endpoint. This SDK still asks for the original shape, and +its models read either one. The newer names are attributes already; the +older ones keep working, with the meaning they always had: + +| Read this | Instead of (deprecated, still works) | +|---|---| +| `ExtractedClaims.claims` (each `.claim`, `.positions`) | `claim`, `identified_claims`, `locations` | +| `AssessClaim.status` (`"completed"` / `"failed"`) and `.failure` | `verdict == "Error"`, `error_code`, `hint` | +| `AssessClaim.more_claims`, `ReviewAssessment.more_claims` | `identified_claims` | +| `AssessResponse.status` and `.failure` | `error`, `error_code` | +| `TaskStatus.failure` (`code`, `detail`, `hint`, `failure_class`, `retryable`, `docs_url`) | `error`, `failure_reason` and the flat fields | +| `TaskAccepted.claim`, `BatchItemResult.claim`, `CandidateClaim.claim` | `claim_text`, `text` | +| `Verification.completed_at` | `modified_at` | +| `ReviewSummary.claim_limit_exceeded`, `citation_limit_exceeded` | `claim_limit_reached`, `citation_limit_reached` | +| `FailureBlock.code`, `.detail` | `failure_reason` | +| `Usage.credits` and `Usage.costs` | the `verify` / `ask` / `assess` blocks, `quota_resets_at` | + +"Nothing checkable" is `no_checkable_claim` in the newer names; the older +fields keep their own spelling (`not_a_claim`, `no_claim`). `model_dump()` +returns the shape the server sent. + ### A suggested rewrite (`suggested_rewrite`) A verification can carry `suggested_rewrite`: a suggested rewrite of its @@ -644,13 +668,13 @@ them. `credits.extra` is the non-expiring part of the balance. Its old name, `credits.bonus`, is deprecated: the same number, it emits a -`DeprecationWarning` when read and goes away on 2026-11-29. +`DeprecationWarning` when read and is kept for existing code. Per-capability `bonus` is that capability's share of `credits.extra`, so 200 extra credits read as `assess.bonus == 200` and `verify.bonus == 20`. The old `capability.credits` field is a deprecated alias of `bonus` (it never meant -the pool); reading it emits a `DeprecationWarning` and it goes away on -2026-11-29. +the pool); reading it emits a `DeprecationWarning` and it is kept for +existing code. ### Depth pricing @@ -815,7 +839,7 @@ At most 300 characters. A longer focus is rejected with a 422 rather than truncated, so you never get a subset you did not ask for. When the document has claims but none fall within your focus, `status` is -`"no_match"` and `identified_claims` is empty. The unfocused list is never +`"no_match"` and `claims` is empty. The unfocused list is never substituted — widen the focus and call again. ```python @@ -838,27 +862,24 @@ to your text, and to learn where the text makes each one: ```python out = client.extract(text=draft, locate=True) -for loc in out.locations or []: - for pos in loc.positions or []: - print(loc.claim, "->", pos.text) +for c in out.claims: + for pos in c.positions or []: + print(c.claim, "->", pos.text) if pos.start is not None: assert draft[pos.start : pos.end] == pos.text ``` A claim found nowhere in the text, or found with a different figure, is left -out; if that leaves no claim, `status` is `"not_a_claim"`. `locations` has one -`ClaimLocation` per returned claim, in the order of `identified_claims` (one -entry for a single `claim`), each with its `positions` (every place the text -makes it, in text order, at least one and at most 10). Each is a `Position`: +out; if that leaves no claim, `status` is `"not_a_claim"`. Each entry of +`claims` has its `positions` (every place the text makes it, in text order, +at least one and at most 10). Each is a `Position`: `start` and `end` index the text you sent in Unicode code points, so `text[start:end]` works natively; `end` is exclusive. Both are `None` when the input was a URL, since the page is not returned; `pos.text` carries the passage. -`locations` is `[]` when every claim was left out (`status` is then -`"not_a_claim"`), and `None` when `locate` was not set, when the extraction -found no claims, or -when the claims could not be located — the list is then returned unfiltered. +`positions` is `None` when `locate` was not set, or when the claims could not +be located — the list is then returned unfiltered. Locating adds a few seconds. `locate` defaults to off; leave it `None` to use the server default, or pass `False` to turn it off explicitly. diff --git a/openapi.json b/openapi.json index f53bc7d..97c8a8b 100644 --- a/openapi.json +++ b/openapi.json @@ -411,7 +411,7 @@ } } }, - "description": "Return the calling account's credit balance and what it can still buy.\n\n**``credits`` is the balance.** One pool funds every billable capability,\nat the weights in ``costs`` \u2014 today ``verify`` 10, ``assess`` 1, ``ask`` 1.\nIt has two buckets: the monthly allowance for the current ``plan``, which\nresets at ``resets_at``, and non-expiring ``extra`` credits from grants and\ntop-ups, spent only once the allowance is gone. ``remaining`` is the sum,\nand is what a call is actually checked against.\n\n``credits.bonus`` is the deprecated old name of ``credits.extra``, the same\nnumber, removed on **2026-11-29** with the fields below. Read ``extra``.\n\n``plan`` is the stable slug to branch on; ``plan_label`` is the same tier\nas display copy (\"Pro\"). Two fields rather than one humanised\nstring, so a reworded label cannot break a client comparing tiers.\nThe Pro plan's ``plan`` is ``pro``; it read ``developer`` before\n2026-09-15 (#664), while ``plan_label`` already read \"Pro\".\n\n**The per-capability blocks are deprecated.** ``verify`` / ``ask`` /\n``assess`` are **projections** of that one pool into each capability's own\nunit \u2014 \"how many of these could I still make\" \u2014 not separate allowances.\nSpending on one moves all of them, and they are floor divisions, so a\nverify block ticks once per 10 credits spent anywhere.\n\nThey go on **2026-11-29**, together with the per-block ``credits`` alias.\nDerive them instead::\n\n remaining = credits.remaining // costs[capability]\n total = credits.total // costs[capability]\n used = total - remaining\n\nTwo capabilities at the same price emit identical blocks \u2014 ``ask`` and\n``assess`` are both 1 credit \u2014 which is the clearest sign the shape\ndescribes an allowance that no longer exists.\n\n``bonus`` in each block is ``credits.extra`` in that capability's unit. The\nolder key ``credits`` is its deprecated alias, on the same date.\n\n``costs`` is one entry per capability at its DEFAULT price. Prices that\ndepend on a request parameter live in ``cost_options``, nested capability\n\u2192 parameter \u2192 value \u2014 ``{\"verify\": {\"depth\": {\"standard\": 10, \"low\": 5}}}``.\nTwo maps rather than a flat one with a ``verify_low`` key, so a future\ntuning parameter nests instead of adding an entry that reads like a fifth\ncapability. Every capability in ``cost_options`` also appears in ``costs``\nat its default, so reading only ``costs`` is always correct.\n\n``extract`` is free at the pool (``costs.extract`` is 0) and is bounded by\na per-account daily fair-use cap instead, reported separately here and\nrejected with 429 rather than 402.", + "description": "Return the calling account's credit balance and what it can still buy.\n\n**``credits`` is the balance.** One pool funds every billable capability,\nat the weights in ``costs`` \u2014 today ``verify`` 10, ``assess`` 1, ``ask`` 1.\nIt has two buckets: the monthly allowance for the current ``plan``, which\nresets at ``resets_at``, and non-expiring ``extra`` credits from grants and\ntop-ups, spent only once the allowance is gone. ``remaining`` is the sum,\nand is what a call is actually checked against.\n\n``credits.bonus`` is the deprecated old name of ``credits.extra``, the same\nnumber, deprecated with the fields below and kept for existing callers. Read ``extra``.\n\n``plan`` is the stable slug to branch on; ``plan_label`` is the same tier\nas display copy (\"Pro\"). Two fields rather than one humanised\nstring, so a reworded label cannot break a client comparing tiers.\nThe Pro plan's ``plan`` is ``pro``; it read ``developer`` before\n2026-09-15 (#664), while ``plan_label`` already read \"Pro\".\n\n**The per-capability blocks are deprecated.** ``verify`` / ``ask`` /\n``assess`` are **projections** of that one pool into each capability's own\nunit \u2014 \"how many of these could I still make\" \u2014 not separate allowances.\nSpending on one moves all of them, and they are floor divisions, so a\nverify block ticks once per 10 credits spent anywhere.\n\nThey are deprecated, together with the per-block ``credits`` alias, and\nkept for existing callers. Derive them instead::\n\n remaining = credits.remaining // costs[capability]\n total = credits.total // costs[capability]\n used = total - remaining\n\nTwo capabilities at the same price emit identical blocks \u2014 ``ask`` and\n``assess`` are both 1 credit \u2014 which is the clearest sign the shape\ndescribes an allowance that no longer exists.\n\n``bonus`` in each block is ``credits.extra`` in that capability's unit. The\nolder key ``credits`` is its deprecated alias, on the same date.\n\n``costs`` is one entry per capability at its DEFAULT price. Prices that\ndepend on a request parameter live in ``cost_options``, nested capability\n\u2192 parameter \u2192 value \u2014 ``{\"verify\": {\"depth\": {\"standard\": 10, \"low\": 5}}}``.\nTwo maps rather than a flat one with a ``verify_low`` key, so a future\ntuning parameter nests instead of adding an entry that reads like a fifth\ncapability. Every capability in ``cost_options`` also appears in ``costs``\nat its default, so reading only ``costs`` is always correct.\n\n``extract`` is free at the pool (``costs.extract`` is 0) and is bounded by\na per-account daily fair-use cap instead, reported separately here and\nrejected with 429 rather than 402.", "tags": [ "Account" ], @@ -2510,7 +2510,7 @@ "type": "object" }, "MeUsageCreditsOut": { - "description": "The account's credit balance \u2014 the one pool every capability spends.\n\nTwo buckets: the monthly allowance for the current plan (resets at\n``resets_at``) and non-expiring ``extra`` credits from grants and top-ups,\nwhich are spent only once the allowance is gone. ``remaining`` is the sum\nand is what a call is checked against.\n\n``bonus`` is a DEPRECATED alias of ``extra`` (the balance's name until\n2026-09-15), removed on 2026-11-29 with the other deprecated fields on this\nendpoint. It was renamed because the balance holds top-ups you paid for as\nwell as grants.", + "description": "The account's credit balance \u2014 the one pool every capability spends.\n\nTwo buckets: the monthly allowance for the current plan (resets at\n``resets_at``) and non-expiring ``extra`` credits from grants and top-ups,\nwhich are spent only once the allowance is gone. ``remaining`` is the sum\nand is what a call is checked against.\n\n``bonus`` is a DEPRECATED alias of ``extra`` (the balance's name until\n2026-09-15), deprecated with the other deprecated fields on this endpoint and kept\nfor existing callers. It was renamed because the balance holds top-ups you paid for as\nwell as grants.", "properties": { "total": { "default": 0, @@ -2576,7 +2576,7 @@ "type": "object" }, "MeUsageOut": { - "description": "The calling account's credit balance, and what it can still buy.\n\n``credits`` is the balance and ``costs`` is the price list. Those two,\nplus ``cost_options``, are the whole contract for a new integration.\n\nThe ``verify`` / ``ask`` / ``assess`` blocks are DEPRECATED projections of\nthat same pool into each capability's unit, kept until 2026-11-29 for\nclients already reading them.\n\n``extract`` is free at the pool (``costs.extract`` is 0) and carries a\nper-account daily fair-use cap instead; it rejects with 429, not 402.\n\nThe Pro plan's ``plan`` is ``pro`` since 2026-09-15; it was ``developer``\nbefore (#664). ``plan_label`` reads \"Pro\" either way.", + "description": "The calling account's credit balance, and what it can still buy.\n\n``credits`` is the balance and ``costs`` is the price list. Those two,\nplus ``cost_options``, are the whole contract for a new integration.\n\nThe ``verify`` / ``ask`` / ``assess`` blocks are DEPRECATED projections of\nthat same pool into each capability's unit, kept for clients\nalready reading them.\n\n``extract`` is free at the pool (``costs.extract`` is 0) and carries a\nper-account daily fair-use cap instead; it rejects with 429, not 402.\n\nThe Pro plan's ``plan`` is ``pro`` since 2026-09-15; it was ``developer``\nbefore (#664). ``plan_label`` reads \"Pro\" either way.", "properties": { "plan": { "default": "free", @@ -2653,7 +2653,7 @@ "type": "object" }, "MeUsageQuotaOut": { - "description": "DEPRECATED. One capability's share of the pool, projected into its unit.\n\n**Removed 2026-11-29**, with the per-block ``credits`` alias below. Read\n``MeUsageOut.credits`` and ``MeUsageOut.costs`` instead and do the\ndivision \u2014 it is one line, and it is the same one this block does::\n\n remaining = credits.remaining // costs[capability]\n total = credits.total // costs[capability]\n used = total - remaining\n\nThese are **projections, not allowances**. Every billable capability draws\non the single balance in ``MeUsageOut.credits``, at the weight in\n``MeUsageOut.costs``; this block answers \"how many ``/verify`` calls could\nI still make if I spent everything on them\". Spending on any capability\nmoves every block, and the division floors \u2014 a ``verify`` block whose\nweight is 10 ticks once per 10 credits spent anywhere.\n\nThey predate the pool, when each really was its own allowance, and that is\nthe reason to retire them: two capabilities at the same price emit\nbyte-identical objects (``ask`` and ``assess`` are both 1 credit today),\nso the shape suggests a per-capability allowance that no longer exists.\n\n``bonus`` is ``MeUsageOut.credits.extra``, the non-expiring balance, in\nthis capability's unit.\n``quota_used`` is derived as ``quota_total - quota_remaining``, so\n``used + remaining == total`` always holds.\n\n``credits`` is a DEPRECATED alias of ``bonus``, kept for compatibility\nuntil 2026-11-29. It never meant the pool \u2014 before the pool existed it\nmeant this capability's one-off top-up balance, which is exactly what\n``bonus`` now reports.", + "description": "DEPRECATED. One capability's share of the pool, projected into its unit.\n\n**Deprecated**, with the per-block ``credits`` alias below, and kept for\nexisting callers. Read\n``MeUsageOut.credits`` and ``MeUsageOut.costs`` instead and do the\ndivision \u2014 it is one line, and it is the same one this block does::\n\n remaining = credits.remaining // costs[capability]\n total = credits.total // costs[capability]\n used = total - remaining\n\nThese are **projections, not allowances**. Every billable capability draws\non the single balance in ``MeUsageOut.credits``, at the weight in\n``MeUsageOut.costs``; this block answers \"how many ``/verify`` calls could\nI still make if I spent everything on them\". Spending on any capability\nmoves every block, and the division floors \u2014 a ``verify`` block whose\nweight is 10 ticks once per 10 credits spent anywhere.\n\nThey predate the pool, when each really was its own allowance, and that is\nthe reason to retire them: two capabilities at the same price emit\nbyte-identical objects (``ask`` and ``assess`` are both 1 credit today),\nso the shape suggests a per-capability allowance that no longer exists.\n\n``bonus`` is ``MeUsageOut.credits.extra``, the non-expiring balance, in\nthis capability's unit.\n``quota_used`` is derived as ``quota_total - quota_remaining``, so\n``used + remaining == total`` always holds.\n\n``credits`` is a DEPRECATED alias of ``bonus``, kept for compatibility\nwith existing callers. It never meant the pool \u2014 before the pool existed it\nmeant this capability's one-off top-up balance, which is exactly what\n``bonus`` now reports.", "properties": { "quota_used": { "default": 0, diff --git a/src/lenz_io/__init__.py b/src/lenz_io/__init__.py index 51c22e2..3fe51ec 100644 --- a/src/lenz_io/__init__.py +++ b/src/lenz_io/__init__.py @@ -18,16 +18,16 @@ # 1. /extract — pull verifiable claims out of text (free, 1000/day) out = client.extract(text=llm_output) - claims = out.identified_claims or [out.claim] + claims = [c.claim for c in out.claims] # 2. /assess — 20 claims a call (extract finds up to 100), one row per claim, same order (paid) quick = [row for i in range(0, len(claims), 20) for row in client.assess(claims=claims[i : i + 20]).claims] - # a row with verdict == "Error" got no verdict: see its error_code and hint; - # a compound item lists the claims it did not assess in identified_claims + # a row with status == "failed" got no verdict: see its failure.code and failure.hint; + # a compound item lists the claims it did not assess in more_claims # 3. /verify — escalate the low-confidence rows to the full pipeline (~90s, paid) # verify_batch_and_wait takes up to 20 claims a call: the first 20 here - doubtful = [{"claim": c.claim} for c in quick if c.verdict != "Error" and c.confidence == "low"][:20] + doubtful = [{"claim": c.claim} for c in quick if c.status == "completed" and c.confidence == "low"][:20] results = client.verify_batch_and_wait(claims=doubtful) if doubtful else [] # 4. /ask — follow-up questions grounded on a verification @@ -74,6 +74,7 @@ AssessClaim, Assessment, AssessResponse, + AssessStatus, Audit, BatchAccepted, BatchItemResult, @@ -89,6 +90,7 @@ EntityRef, Escalation, EscalationPolicy, + ExtractedClaim, ExtractedClaims, ExtractedEntity, ExtractStatus, @@ -144,6 +146,7 @@ "AskReply", "AssessClaim", "AssessResponse", + "AssessStatus", "Assessment", "Audit", "BatchAccepted", @@ -166,6 +169,7 @@ "Escalation", "EscalationPolicy", "ExtractStatus", + "ExtractedClaim", "ExtractedClaims", "ExtractedEntity", "FailureBlock", diff --git a/src/lenz_io/cli/render.py b/src/lenz_io/cli/render.py index 80e7e05..753cfca 100644 --- a/src/lenz_io/cli/render.py +++ b/src/lenz_io/cli/render.py @@ -109,15 +109,12 @@ def render_extract(out: Output, result: ExtractedClaims) -> None: if out.json_mode: out.emit_json(_model_json(result)) return - # The server splits a claim set across two fields: the primary claim lands - # in ``claim`` and any extras in ``identified_claims``. Neither alone is the - # full list — the primary is usually NOT echoed into ``identified_claims`` — - # so render the union so the primary is never dropped (and the count is - # right). Single-claim input → just ``claim``. - primary = (getattr(result, "claim", "") or "").strip() - claims = [primary] if primary else [] - for c in result.identified_claims or []: - c = (c or "").strip() + # ``claims`` is the whole list, from either response shape (the model + # builds it from ``claim`` + ``identified_claims`` when that is what the + # server sent). Blank and repeated entries are dropped. + claims: list[str] = [] + for item in result.claims: + c = (item.claim or "").strip() if c and c not in claims: claims.append(c) if len(claims) > 1: @@ -151,7 +148,7 @@ def _render_positions(out: Output, result: ExtractedClaims, claim: str, *, inden input, where there is nothing to index) and the passage itself. The passage is the user's own text, so it prints with ``markup=False``. """ - for loc in result.locations or []: + for loc in result.claims: if (loc.claim or "").strip() != claim: continue for pos in loc.positions or []: @@ -171,9 +168,10 @@ def render_assess(out: Output, result: AssessResponse) -> None: return for c in claims: color = _VERDICT_COLOR.get(c.verdict, "white") - # An Error row (list form) names its cause in place of the confidence, - # which is meaningless there. - detail = c.error_code if c.verdict == "Error" and c.error_code else c.confidence + # A failed row (list form) names its cause in place of the confidence, + # which is meaningless there. ``error_code`` is the cause in its + # original spelling, from either response shape. + detail = c.error_code if c.status == "failed" and c.error_code else c.confidence out.console.print(f"[{color}]{c.verdict or '?'}[/{color}] ({detail}) — {c.claim}") # The reviewers' notes, as plain text: `markup=False` because the # words are a model's, and a stray "[bold]" in them is not ours. @@ -181,9 +179,9 @@ def render_assess(out: Output, result: AssessResponse) -> None: out.console.print(f" {c.rationale}", markup=False, highlight=False) if c.dissent: out.console.print(f" One reviewer disagreed: {c.dissent}", markup=False, highlight=False) - if c.identified_claims: + if c.more_claims: out.console.print(" [dim]also found:[/dim]") - for other in c.identified_claims: + for other in c.more_claims: out.console.print(f" • {other}") if c.hint: out.console.print(f" [dim]{c.hint}[/dim]") @@ -395,7 +393,7 @@ def render_task_status(out: Output, st: TaskStatus, *, task_id: str = "") -> Non if st.claims: out.console.print("[dim]claims found:[/dim]") for i, claim in enumerate(st.claims, 1): - out.console.print(f" {i}. {claim.text}") + out.console.print(f" {i}. {claim.claim}") ref = task_id or "" # Non-interactive resolution (agents/scripts): `--claim` picks by index # and `--detach` returns the spawned task_id(s) without blocking. Drop diff --git a/src/lenz_io/cli/verify.py b/src/lenz_io/cli/verify.py index 0deb9e3..f0ca5a5 100644 --- a/src/lenz_io/cli/verify.py +++ b/src/lenz_io/cli/verify.py @@ -198,7 +198,7 @@ def _poll( # Sub-claims inherit the parent submission's depth server-side # (/select reads it off the task meta), so nothing to send here. items = client.select(task_id, claims=texts).items - picks = [(it.task_id, it.claim_text or txt) for it, txt in zip(items, texts, strict=True)] + picks = [(it.task_id, it.claim or txt) for it, txt in zip(items, texts, strict=True)] # detach, or >1 claim → batch path; exactly one → keep the # single-verdict flow (nicer than a 1-row table). if detach or len(picks) > 1: @@ -256,7 +256,7 @@ def _resolve_multi_claim(out: Output, task_id: str, st: TaskStatus, selection: l Otherwise json mode emits the needs_input object and exits 3 (never hangs on a prompt that can't happen); a TTY shows the checkbox picker. """ - options = [c.text for c in st.claims] + options = [c.claim for c in st.claims] if selection is not None: return [options[i] for i in _selection_to_indices(selection, len(options))] if out.json_mode: diff --git a/src/lenz_io/client.py b/src/lenz_io/client.py index b496e3b..b45141e 100644 --- a/src/lenz_io/client.py +++ b/src/lenz_io/client.py @@ -201,8 +201,13 @@ def _batch_item_body(item: Any) -> Any: An item without ``claim`` is forwarded verbatim, so every existing caller keeps a byte-identical request body. An item with ``claim`` is sent as - ``text`` — the wire key the server has always accepted. + ``text`` — the wire key the server has always accepted. An empty + ``webhook_url`` is left out, as on the batch itself: it has always meant + the key's default, and leaving it out keeps that meaning on every API + version. """ + if isinstance(item, dict) and item.get("webhook_url") == "": + item = {k: v for k, v in item.items() if k != "webhook_url"} if "claim" not in item: return item body = {k: v for k, v in item.items() if k != "claim"} @@ -659,18 +664,18 @@ def extract( one an unfocused call would have returned too, verbatim. When the text has claims but none fall within the focus, ``status`` - is ``"no_match"`` and ``identified_claims`` is empty — the unfocused + is ``"no_match"`` and ``claims`` is empty — the unfocused list is never substituted. Widen the focus and call again. A focused call costs the same single unit of the daily cap. ``locate`` (optional): with ``True``, only the claims that could be - traced directly back to the text are returned, and ``locations`` - says where the text makes each one (``start``/``end`` index the + traced directly back to the text are returned, and each claim's + ``positions`` says where the text makes it (``start``/``end`` index the ``text`` you sent, in code points, so ``text[start:end]`` is the passage). A claim found nowhere in the text, or found with a different figure, is left out; if that leaves no claim, ``status`` is ``"not_a_claim"``. Locating adds a few seconds. If the claims - cannot be located, ``locations`` is ``None`` and the list is returned + cannot be located, ``positions`` is ``None`` and the list is returned unfiltered. Leave it ``None`` to use the server default (currently off); an explicit ``False`` is sent as such. @@ -720,7 +725,7 @@ def assess( ``extract`` in the ladder:: out = client.extract(text=llm_output) - claims = out.identified_claims or [out.claim] + claims = [c.claim for c in out.claims] quick = [row for i in range(0, len(claims), 20) # 20 a call for row in client.assess(claims=claims[i : i + 20]).claims] @@ -733,14 +738,16 @@ def assess( ``verification_url`` pointing at the deep ``Verification`` when /assess found a matching stored claim. - A row with ``verdict == "Error"`` could not be given a verdict. It - stays in position, is not charged, and says why: ``error_code`` is - ``no_claim`` / ``framing_failed`` / ``upstream_unavailable`` / - ``timeout`` (an open set; the last two are worth resending as-is), and - ``hint`` is one sentence on what to send next. A compound list item is assessed on its main - claim; the other claims found in it are listed on that row in - ``identified_claims`` (with a ``hint``) — send them as their own - items to check the rest. ``hint`` is ``None`` on a plain verdict row. + A row with ``status == "failed"`` could not be given a verdict (its + ``verdict`` reads ``"Error"``). It stays in position, is not charged, + and says why: ``failure.code`` is ``no_checkable_claim`` / + ``framing_failed`` / ``upstream_unavailable`` / ``timeout`` (an open + set; the last two are worth resending as-is), and ``failure.hint`` is + one sentence on what to send next. A compound list item is assessed on + its main claim; the other claims found in it are listed on that row in + ``more_claims`` — send them as their own items to check the rest. + (The deprecated ``error_code``, ``hint`` and ``identified_claims`` keep + their original meaning.) Use ``confidence`` to decide when to escalate: ``"low"`` rows are worth re-running through ``verify_batch_and_wait`` for the deep @@ -978,19 +985,21 @@ def verify_batch_and_wait( terminal, timed_out, gone = self._poll_to_terminal(ids, timeout, on_progress) results: list[BatchItemResult] = [] + # Built with ``claim_text`` so ``model_dump()`` keeps the keys it has + # always had; ``BatchItemResult.claim`` reads the same string. for it in accepted.items: # preserve input order status = terminal.get(it.task_id) if it.task_id in gone: # Removed by the account's retention period (410): terminal, # with no status to carry. - results.append(BatchItemResult(task_id=it.task_id, claim_text=it.claim_text, status="failed")) + results.append(BatchItemResult(task_id=it.task_id, claim_text=it.claim, status="failed")) elif not it.task_id or it.task_id in timed_out or status is None: - results.append(BatchItemResult(task_id=it.task_id, claim_text=it.claim_text, status="timeout")) + results.append(BatchItemResult(task_id=it.task_id, claim_text=it.claim, status="timeout")) elif status.status == "completed" and status.result is not None: results.append( BatchItemResult( task_id=it.task_id, - claim_text=it.claim_text, + claim_text=it.claim, status="completed", verification=status.result, status_detail=status, @@ -998,14 +1007,12 @@ def verify_batch_and_wait( ) elif status.status == "needs_input": results.append( - BatchItemResult( - task_id=it.task_id, claim_text=it.claim_text, status="needs_input", status_detail=status - ) + BatchItemResult(task_id=it.task_id, claim_text=it.claim, status="needs_input", status_detail=status) ) else: # failed, or completed-without-result (treated as failed). results.append( - BatchItemResult(task_id=it.task_id, claim_text=it.claim_text, status="failed", status_detail=status) + BatchItemResult(task_id=it.task_id, claim_text=it.claim, status="failed", status_detail=status) ) return results @@ -1521,6 +1528,8 @@ def _verification_from_terminal(self, status: TaskStatus, task_id: str) -> Verif ) # failed. Server sends the diagnostic under ``error``; fall back to the # legacy fields for resilience. + # ``failure.detail`` is the sentence in the newer response shape; + # ``error`` carries the original one (and is filled from the block). detail = status.error or status.failure_detail or status.failure_reason or "unknown" if status.retryable: fix = "Transient provider outage — retry the same request after a short wait." @@ -1564,8 +1573,12 @@ def _verify_submit( payload: dict[str, Any] = { "text": claim or text, "source_url": source_url, - "webhook_url": webhook_url, } + # Omit-when-empty: no ``webhook_url`` means the key's default webhook. + # An empty string is never sent, so a request keeps that meaning on + # every API version (a newer one reads ``""`` as "no webhook"). + if webhook_url: + payload["webhook_url"] = webhook_url # Omit-when-empty so existing English callers keep byte-identical # request bodies (no extra "language": "" key). if language: @@ -1598,7 +1611,10 @@ def _verify_batch( # ``VerifyBatchItem`` TypedDict is purely for IDE autocompletion # (revised SDK plan decision 1C — no Pydantic coercion, keep the # runtime contract a plain dict). - payload: dict[str, Any] = {"claims": [_batch_item_body(c) for c in claims], "webhook_url": webhook_url} + payload: dict[str, Any] = {"claims": [_batch_item_body(c) for c in claims]} + # Omit-when-empty, as on ``verify``: no ``webhook_url`` means the key's default. + if webhook_url: + payload["webhook_url"] = webhook_url if language: payload["language"] = language if visibility: diff --git a/src/lenz_io/errors.py b/src/lenz_io/errors.py index 07662e4..47c9583 100644 --- a/src/lenz_io/errors.py +++ b/src/lenz_io/errors.py @@ -192,7 +192,9 @@ class LenzValidationError(LenzError): """422 — request body failed schema validation. ``errors`` is a list of per-field error dicts as returned by Ninja: - ``[{"loc": [...], "msg": "...", "type": "..."}]``. + ``[{"loc": [...], "msg": "...", "type": "..."}]``, read from the body's + ``detail`` list (the original response shape) or its ``errors`` list + (the newer one, where ``detail`` is a sentence and becomes the message). """ errors: list[dict[str, Any]] = [] # noqa: RUF012 — overridden per-instance @@ -202,7 +204,8 @@ class LenzRateLimitError(LenzError): """429 — rate limited. * ``retry_after`` — seconds until the next allowed call, resolved - from the ``Retry-After`` header or the body's ``reset_in_seconds``. + from the ``Retry-After`` header or the body's ``reset_in_seconds`` / + ``retry_after``. * ``limit`` — the cap that was hit, when the server states it. * ``reset_in_seconds`` — the body's raw echo of the same wait. @@ -431,6 +434,10 @@ class LenzWebhookSignatureError(LenzError): # inside a submit would block the caller, most likely into the same answer. NO_RETRY_429_CODES = ("review_in_flight",) +# The 429s that refuse a submit while the account's earlier ones run. They +# stated their wait as ``retry_after_seconds``, never ``reset_in_seconds``. +_IN_FLIGHT_429_CODES = ("review_in_flight", "citecheck_in_flight") + _STATUS_MAP: dict[int, tuple[type[LenzError], str, str]] = { 401: ( LenzAuthError, @@ -561,18 +568,24 @@ def map_response_to_error( if status_code == 409 and isinstance(err, (LenzVerificationNotReadyError, LenzPipelineError)): # The generic 4xx advice ("retry; file an issue") is wrong for both: # the server's own hint says what to do, with a class default behind it. + # A failed run states its cause flat in the original response shape + # and in one ``failure`` block in the newer one; read both, flat first. + raw_failure = parsed.get("failure") + failure: dict[str, Any] = raw_failure if isinstance(raw_failure, dict) else {} err.task_id = _opt_str(parsed.get("task_id")) - err.hint = _opt_str(parsed.get("hint")) + err.hint = _opt_str(parsed.get("hint")) or _opt_str(failure.get("hint")) if isinstance(err, LenzVerificationNotReadyError): err.status = _opt_str(parsed.get("status")) err.fix = err.hint or "Wait for the run with client.wait(task_id), then read its result." else: - err.failure_reason = _opt_str(parsed.get("failure_reason")) - err.failure_class = _opt_str(parsed.get("failure_class")) + reason = _opt_str(parsed.get("failure_reason")) or _opt_str(failure.get("code")) + # The original spelling of "nothing checkable" on a verification. + err.failure_reason = "not_a_claim" if reason == "no_checkable_claim" else reason + err.failure_class = _opt_str(parsed.get("failure_class")) or _opt_str(failure.get("failure_class")) # Only a real boolean is a retry signal, as in the wait path. - retryable = parsed.get("retryable") + retryable = parsed.get("retryable", failure.get("retryable")) err.retryable = retryable if isinstance(retryable, bool) else None - err.doc_url = _opt_str(parsed.get("docs_url")) or err.doc_url + err.doc_url = _opt_str(parsed.get("docs_url")) or _opt_str(failure.get("docs_url")) or err.doc_url if err.hint: err.fix = err.hint elif err.retryable: @@ -609,6 +622,12 @@ def map_response_to_error( # sending null precisely so "unknown" stays distinguishable from # "zero". Collapsing that here would throw the distinction away. err.remaining = _opt_int(parsed.get("remaining")) + if err.remaining is None and "remaining" not in parsed and "requested" not in parsed: + # A body without the capability figure (the newer response shape + # on some endpoints): the pool divided by this one call's price. + pool, price = _opt_int(parsed.get("credits_remaining")), _opt_int(parsed.get("cost")) + if pool is not None and price: + err.remaining = pool // price err.requested = _opt_int(parsed.get("requested")) # The pool behind the capability figure above, and this call's price in # credits. The body's ``credits_remaining`` lands on ``credit_balance``, @@ -630,6 +649,10 @@ def map_response_to_error( elif isinstance(err, LenzRateLimitError): err.limit = _opt_int(parsed.get("limit")) err.reset_in_seconds = _opt_int(parsed.get("reset_in_seconds")) + if err.reset_in_seconds is None and code not in _IN_FLIGHT_429_CODES: + # The newer response shape names every wait ``retry_after``. The + # in-flight refusals never carried ``reset_in_seconds``. + err.reset_in_seconds = _opt_int(parsed.get("retry_after")) rl_upgrade_url = parsed.get("upgrade_url") err.upgrade_url = rl_upgrade_url if isinstance(rl_upgrade_url, str) else "" # Header first, then the body. `reset_in_seconds` is what the server diff --git a/src/lenz_io/models.py b/src/lenz_io/models.py index 335d52f..d6146d9 100644 --- a/src/lenz_io/models.py +++ b/src/lenz_io/models.py @@ -12,16 +12,68 @@ - ``claim`` : str — the framed claim text - ``verdict`` : str — "True" | "Mostly True" | "Mixed" | "Mostly False" | "False" | "Error" + ("Error": an ``assess`` row with ``status == "failed"``) - ``confidence`` : str — "high" | "medium" | "low" (categorical) - ``lenz_score`` : int | None - 1-10 integer (deep / list; /assess omits) """ from __future__ import annotations -from collections.abc import ItemsView, KeysView, ValuesView +import functools +from collections.abc import Callable, ItemsView, KeysView, ValuesView +from datetime import datetime, timezone from typing import Any, Literal -from pydantic import BaseModel, ConfigDict, Field, model_validator +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + SerializerFunctionWrapHandler, + model_serializer, + model_validator, +) + +#: Where a validator lists the attributes it filled in that the response did +#: not carry. ``_Lax`` moves it to a private attribute; ``model_dump()`` leaves +#: those attributes out, so a dump is always the shape the server sent. +_DERIVED_KEY = "__lenz_derived__" + + +def _reads_both(*new_fields: str, always_hide: bool = False) -> Callable[[Callable[..., Any]], Callable[..., Any]]: + """Mark what a ``_read_both_shapes`` validator derived, so ``model_dump()`` + shows the shape the server sent. + + ``new_fields`` are the attributes this release added for the newer + response shape. Hidden from a dump: each of them the input did not carry + (so an original-shape response dumps exactly as it did before this + release), and, on a newer-shape input (one carrying any of them, or any + input with ``always_hide``), every attribute the input did not carry. A + value the validator rewrote (a failed row's ``verdict``) dumps as sent. + """ + + def wrap(fn: Callable[..., Any]) -> Callable[..., Any]: + @functools.wraps(fn) + def inner(cls: Any, data: Any) -> Any: + out = fn(cls, data) + if not isinstance(data, dict) or not isinstance(out, dict): + return out + hidden = {k for k in new_fields if k not in data} + if always_hide or any(k in data for k in new_fields): + hidden |= {k for k in out if k not in data} + hidden |= {k for k in cls.model_fields if k not in data} + rewritten = { + k: v + for k, v in data.items() + if k in out and not isinstance(v, (dict, list)) and out[k] is not v and out[k] != v + } + if not hidden and not rewritten: + return out + return {**out, _DERIVED_KEY: {"hidden": sorted(hidden), "sent": rewritten}} + + return inner + + return wrap class _Lax(BaseModel): @@ -35,6 +87,106 @@ class _Lax(BaseModel): model_config = ConfigDict(extra="allow") + # The attributes filled in from the other response shape (see + # ``_reads_both``): readable, never dumped. + _lenz_derived: frozenset[str] = PrivateAttr(default_factory=frozenset) + _lenz_sent: dict[str, Any] = PrivateAttr(default_factory=dict) + + @model_validator(mode="after") + def _collect_derived(self) -> Any: + extra = self.__pydantic_extra__ + if extra and _DERIVED_KEY in extra: + marks = extra.pop(_DERIVED_KEY) + self._lenz_derived = frozenset(marks["hidden"]) + self._lenz_sent = dict(marks["sent"]) + return self + + @model_serializer(mode="wrap") + def _dump_as_sent(self, handler: SerializerFunctionWrapHandler) -> Any: + data = handler(self) + if isinstance(data, dict): + for key in self._lenz_derived: + data.pop(key, None) + for key, value in self._lenz_sent.items(): + if key in data: + data[key] = value + return data + + +# ── Reading both response shapes ───────────────────────────────────────── +# +# The API is gaining a second, dated response shape that renames a handful of +# fields (``claim_text`` -> ``claim``, ``modified_at`` -> ``completed_at``, a +# failed item's ``error`` / ``error_code`` / ``failure_reason`` -> one +# ``failure`` block, ...). This release still asks for the original shape, but +# every model reads either one: the new name is a first-class attribute, and +# every old attribute keeps its old meaning, computed from whichever shape +# arrived. The helpers below are the shared rules. + +#: The one code for "the input holds nothing that can be checked", in the +#: newer response shape. The original shape spells it per endpoint: +#: ``not_a_claim`` (/extract, /verify) and ``no_claim`` (/assess, /review). +NO_CHECKABLE_CLAIM = "no_checkable_claim" +_OLD_NO_CLAIM_CODES = ("not_a_claim", "no_claim") + + +def _new_code(code: Any) -> Any: + """An old per-endpoint spelling of "nothing checkable" -> the one new code.""" + return NO_CHECKABLE_CLAIM if code in _OLD_NO_CLAIM_CODES else code + + +def _old_code(code: Any, old: str) -> Any: + """The new code -> the spelling ``old`` this field always carried.""" + return old if code in (NO_CHECKABLE_CLAIM, *_OLD_NO_CLAIM_CODES) else code + + +def _utc_day(iso: Any) -> Any: + """The UTC calendar day of an ISO-8601 string, or ``None``.""" + if not isinstance(iso, str) or not iso: + return None + try: + when = datetime.fromisoformat(iso.replace("Z", "+00:00")) + except ValueError: + return None + if when.tzinfo is None: + when = when.replace(tzinfo=timezone.utc) + return when.astimezone(timezone.utc).date() + + +def _modified_at_from(created_at: Any, completed_at: Any) -> str | None: + """The original ``modified_at`` rule: the completion time when it falls on a + later UTC calendar day than the creation time, else ``None``.""" + created, completed = _utc_day(created_at), _utc_day(completed_at) + if created is None or completed is None or completed <= created: + return None + return str(completed_at) + + +def _with_completion_times(data: Any) -> Any: + """Fill ``completed_at`` and ``modified_at`` from whichever one arrived. + + ``modified_at`` from ``completed_at``: the original later-calendar-day + rule. ``completed_at`` from ``modified_at``: exact when ``modified_at`` is + set; when it is null (a same-day completion) the original shape does not + say when the verification completed, so ``completed_at`` stays ``None``. + """ + if not isinstance(data, dict): + return data + if "completed_at" in data and "modified_at" not in data: + return {**data, "modified_at": _modified_at_from(data.get("created_at"), data.get("completed_at"))} + if "modified_at" in data and "completed_at" not in data: + return {**data, "completed_at": data.get("modified_at")} + return data + + +def _mirror(data: dict[str, Any], new: str, old: str) -> dict[str, Any]: + """Copy a field across a plain rename, in whichever direction is missing.""" + if new in data and old not in data: + return {**data, old: data[new]} + if old in data and new not in data: + return {**data, new: data[old]} + return data + #: Closed set of failure causes on a ``failed`` verification, mirroring the #: Node SDK's ``FailureClass`` union. Exported for callers who want exhaustive @@ -112,11 +264,23 @@ class Audit(_Lax): class CandidateClaim(_Lax): - """One of multiple distinct claims framing found in the submitted text.""" + """One of multiple distinct claims framing found in the submitted text. - text: str = "" + ``claim`` is the claim's text. ``text`` is its older name, the same + string, kept for existing code (deprecated; either shape fills both). + """ + + claim: str = "" + #: Deprecated: the same string as :attr:`claim`. + text: str = Field(default="", json_schema_extra={"deprecated": True}) domain: str = "" + @model_validator(mode="before") + @classmethod + @_reads_both("claim") + def _read_both_shapes(cls, data: Any) -> Any: + return _mirror(data, "claim", "text") if isinstance(data, dict) else data + class EntityRef(_Lax): """An entity referenced in the claim. @@ -236,8 +400,9 @@ class Verification(_Lax): endpoint, and the webhook payload. The verdict block is FLAT at top level (was nested ``Verdict`` object - pre-unify). ``created_at`` + ``modified_at`` are the only timestamp - fields on the API surface — editorial ``published_at`` is internal-only. + pre-unify). ``created_at`` and ``completed_at`` are its timestamps + (``modified_at`` is the deprecated older one) — editorial + ``published_at`` is internal-only. 1.1.0: dropped ``url`` and ``visibility``. API claims are private by default and referenced by ``verification_id`` only. Cache-hit on @@ -286,7 +451,13 @@ class Verification(_Lax): sources: list[Source] = Field(default_factory=list) audit: Audit = Field(default_factory=Audit) created_at: str | None = None - modified_at: str | None = None + #: When the verification completed. In the original response shape it is + #: known only through ``modified_at``: set when that is, ``None`` on a + #: same-day completion (and on servers that send neither). + completed_at: str | None = None + #: Deprecated: the completion time when it falls on a later UTC calendar + #: day than ``created_at``, else ``None``. Read :attr:`completed_at`. + modified_at: str | None = Field(default=None, json_schema_extra={"deprecated": True}) # Output language (ISO 639-1). Always populated by the server when # the SDK is fresh; defaulted to ``'en'`` for resilience against # older cached payloads that lack the field. @@ -301,6 +472,12 @@ class Verification(_Lax): #: reasons why. coverage: Coverage | None = None + @model_validator(mode="before") + @classmethod + @_reads_both("completed_at") + def _read_both_shapes(cls, data: Any) -> Any: + return _with_completion_times(data) + class VerificationListItem(_Lax): """Compact item for the verifications list endpoint and the public @@ -321,10 +498,19 @@ class VerificationListItem(_Lax): # A suggested rewrite of ``claim``. See ``Verification.suggested_rewrite``. suggested_rewrite: str | None = None created_at: str | None = None - modified_at: str | None = None + #: See ``Verification.completed_at``. + completed_at: str | None = None + #: Deprecated. See ``Verification.modified_at``. + modified_at: str | None = Field(default=None, json_schema_extra={"deprecated": True}) # Output language (ISO 639-1). See ``Verification.language``. language: str = "en" + @model_validator(mode="before") + @classmethod + @_reads_both("completed_at") + def _read_both_shapes(cls, data: Any) -> Any: + return _with_completion_times(data) + class VerificationList(_Lax): items: list[VerificationListItem] = Field(default_factory=list) @@ -396,7 +582,9 @@ class ClaimLocation(_Lax): #: from lenz_io import ExtractStatus #: #: - ``ready`` — claims were found (and, with a ``focus``, at least one matched). -#: - ``not_a_claim`` — the text holds no verifiable factual claim at all. +#: - ``not_a_claim`` — the text holds no verifiable factual claim at all (the +#: newer response shape spells it ``no_checkable_claim``; this release +#: reads both as ``not_a_claim``). #: - ``no_match`` — claims were found, but none fall within the ``focus``. #: #: A DOCUMENTATION constant, not a guarantee. The model field stays ``str``, @@ -415,27 +603,40 @@ class ClaimLocation(_Lax): ] +class ExtractedClaim(ClaimLocation): + """One claim ``/extract`` found: ``claim``, and with ``locate=True`` its + ``positions`` in the text (``None`` when the call did not locate, or the + claims could not be located).""" + + class ExtractedClaims(_Lax): """Output of ``POST /extract``. + ``claims`` is every claim found, most check-worthy first, always a list + (one entry for one claim, ``[]`` for none). With ``locate=True`` each + entry's ``positions`` says where the text makes it. + ``status`` is one of ``ExtractStatus``: ``ready``, ``not_a_claim``, or — when a ``focus`` was given and no claim fell within it — ``no_match``. - ``no_match`` is a successful answer, not an error: ``identified_claims`` - is empty and the unfocused list is never substituted for it. - - ``locations`` is set only on a call made with ``locate=True``: one - ``ClaimLocation`` per returned claim, in the order of - ``identified_claims`` (one entry for a single ``claim``). It is ``[]`` - when every claim was left out (``status`` is then ``"not_a_claim"``), - and ``None`` when ``locate`` was not set, when the extraction found no - claims, or when the - claims could not be located (the list is then returned unfiltered). - Older servers omit the key; it parses as ``None``. + ``no_match`` is a successful answer, not an error: ``claims`` is empty + and the unfocused list is never substituted for it. In this release + ``status`` keeps the ``not_a_claim`` spelling whichever response shape + arrived (the newer shape spells it ``no_checkable_claim``). + + Deprecated, kept with their original meaning: ``claim`` is the first + claim (``""`` for none), ``identified_claims`` the whole list when there + are two or more (``[]`` for one), and ``locations`` the ``ClaimLocation`` + list of a located call (``None`` when ``locate`` was not set, when the + extraction found no claims, or when the claims could not be located). + Read ``claims`` instead: it is filled from either response shape. """ status: str = "" - claim: str = "" - identified_claims: list[str] = Field(default_factory=list) + claims: list[ExtractedClaim] = Field(default_factory=list) + #: Deprecated: the first of :attr:`claims`. + claim: str = Field(default="", json_schema_extra={"deprecated": True}) + #: Deprecated: :attr:`claims` when there are two or more, else ``[]``. + identified_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) # Deprecated: always empty since 2026-09-12. Kept because the server # still sends the key. candidate_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) @@ -443,7 +644,84 @@ class ExtractedClaims(_Lax): key_entities: list[ExtractedEntity] = Field(default_factory=list) presumed_intent: str = "" original_input: str = "" - locations: list[ClaimLocation] | None = None + #: Deprecated: the ``positions`` of :attr:`claims`, as one + #: ``ClaimLocation`` per claim. + locations: list[ClaimLocation] | None = Field(default=None, json_schema_extra={"deprecated": True}) + + @model_validator(mode="before") + @classmethod + @_reads_both("claims") + def _read_both_shapes(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + out = dict(data) + if out.get("status") == NO_CHECKABLE_CLAIM: + out["status"] = "not_a_claim" + claims = out.get("claims") + if isinstance(claims, list): + # The newer shape: derive the three original fields. + items = [c for c in claims if isinstance(c, dict)] + names = [str(c.get("claim") or "") for c in items] + out.setdefault("claim", names[0] if names else "") + out.setdefault("identified_claims", names if len(names) > 1 else []) + if "locations" not in out: + located = bool(items) and all(c.get("positions") is not None for c in items) + out["locations"] = ( + [{"claim": c.get("claim") or "", "positions": c.get("positions")} for c in items] + if located + else None + ) + return out + # The original shape: build ``claims`` from ``claim`` + ``identified_claims``. + identified = [c for c in out.get("identified_claims") or [] if isinstance(c, str)] + primary = out.get("claim") if isinstance(out.get("claim"), str) else "" + # ``identified_claims`` normally starts with ``claim``; an older server + # sent the extras only, so take the union, ``claim`` first. + names = ([primary] if primary else []) + [c for c in identified if c != primary] + positions: dict[str, Any] = {} + for loc in out.get("locations") or []: + if isinstance(loc, dict) and isinstance(loc.get("claim"), str): + positions.setdefault(loc["claim"], loc.get("positions")) + out["claims"] = [{"claim": n, "positions": positions.get(n)} for n in names] + return out + + +class FailureBlock(_Lax): + """Why something failed: a review, one claim's work inside it, a citation + check, an ``assess`` row or a verification. + + ``code`` is the specific cause (an open set, e.g. ``no_checkable_claim``, + ``insufficient_credits``, ``timeout``), ``detail`` one sentence on what + happened (``None`` from the original response shape, which has no such + sentence here), ``failure_class`` the closed :data:`FailureClass`, + ``retryable`` whether resending the same request can help, ``hint`` one + sentence on what to do next and ``docs_url`` where the class is explained. + + ``failure_reason`` is the older name of ``code`` (deprecated), with its + original spelling: ``no_claim`` where ``code`` reads + ``no_checkable_claim``. Either response shape fills both. + """ + + code: str | None = "" + detail: str | None = None + #: Deprecated: :attr:`code`, spelling "nothing checkable" ``no_claim``. + failure_reason: str | None = Field(default="", json_schema_extra={"deprecated": True}) + failure_class: str | None = "" + retryable: bool | None = None + hint: str | None = None + docs_url: str | None = "" + + @model_validator(mode="before") + @classmethod + @_reads_both("code", "detail") + def _read_both_shapes(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + if "code" in data and "failure_reason" not in data: + return {**data, "failure_reason": _old_code(data["code"], "no_claim")} + if "failure_reason" in data and "code" not in data: + return {**data, "code": _new_code(data["failure_reason"])} + return data class AssessClaim(_Lax): @@ -454,29 +732,38 @@ class AssessClaim(_Lax): ``ClaimDetailOut`` payload at ``GET /api/v1/verifications/{id}`` for callers that want citations and the full audit trail. - A row with ``verdict == "Error"`` could not be given a verdict. On a - list call it stays in position (one row per item sent), is not charged, - and says why: ``error_code`` names the cause and ``hint`` is one - sentence on what to send next. ``hint`` is the field to surface to a - human — it is written per cause and stays correct as causes are added. - A vague input is assessed on its most likely reading, which ``claim`` - carries. A compound input is assessed on its main claim; the other - claims found in it are listed in ``identified_claims`` (also with a - ``hint``). These fields default empty so older servers that don't send - them still parse. + ``status`` is ``"completed"`` for a row with a verdict and ``"failed"`` + for one that could not be given a verdict. A failed row stays in + position (one row per item sent on a list call), is not charged, and + says why in ``failure``: ``failure.code`` names the cause and + ``failure.hint`` is one sentence on what to send next — the field to + surface to a human, written per cause. A vague input is assessed on its + most likely reading, which ``claim`` carries. A compound input is + assessed on its main claim; the other claims found in it are listed in + ``more_claims``. + + The original fields keep their meaning whichever response shape + arrived: a failed row reads ``verdict == "Error"`` and + ``confidence == "low"``, its cause is in ``error_code`` (``no_claim`` + where ``failure.code`` reads ``no_checkable_claim``) and its next step in + ``hint``; ``identified_claims`` is ``more_claims``. These fields default + empty so older servers that don't send them still parse. """ claim: str = "" # Output language (ISO 639-1). Echoes the language requested on the # call, or ``'en'`` when unspecified. Verdict enums always English. language: str = "en" + #: ``"completed"`` (a verdict) or ``"failed"`` (none; see ``failure``). + #: ``""`` only from a server that sent neither a status nor a verdict. + status: str = "" verdict: str = "" # "True" | "Mostly True" | "Mixed" | "Mostly False" | "False" | "Error" confidence: str = "low" # "high" | "medium" | "low" verification_url: str | None = None # ``rationale`` is the reasoning of a reviewer who agrees with the panel's # verdict; ``dissent``, when set, is the reasoning of the reviewer farthest # from it. Both are reviewers' notes, not checked sources; for sourced - # evidence, call ``verify``. Read both as optional: an ``"Error"`` row has + # evidence, call ``verify``. Read both as optional: a failed row has # neither, and a response replayed from before the API added them carries # neither key. rationale: str | None = None @@ -489,28 +776,75 @@ class AssessClaim(_Lax): # check's reasoning and not itself verified: review it, or run it through # ``verify``, before using it. suggested_rewrite: str | None = None - # Only on ``verdict == "Error"`` rows: 'no_claim' | 'framing_failed' | - # 'upstream_unavailable' | 'timeout'. - # - # An OPEN set, deliberately typed ``str`` rather than a Literal: the API - # may add a cause in a minor version, so branch on the ones you know and - # fall through on the rest. - # - # Which are worth resending as-is: 'upstream_unavailable' (a provider was - # down) and 'timeout' (the call ran out of its time budget before this - # item was done — send fewer items per call to make it less likely). - # 'framing_failed' is deterministic, so retrying the same text will not - # help (a provider outage comes back as 'upstream_unavailable' instead). - # 'no_claim' wants a different input; read ``hint``. - error_code: str | None = None + #: Why a failed row has no verdict; ``None`` on a completed row. + #: ``failure.code`` is an OPEN set (``no_checkable_claim`` | + #: ``framing_failed`` | ``upstream_unavailable`` | ``timeout`` today): + #: branch on the ones you know and fall through on the rest. + #: + #: Which are worth resending as-is: ``upstream_unavailable`` (a provider + #: was down) and ``timeout`` (the call ran out of its time budget before + #: this item was done — send fewer items per call to make it less likely). + #: ``framing_failed`` is deterministic, so retrying the same text will not + #: help. ``no_checkable_claim`` wants a different input; read + #: ``failure.hint``. + failure: FailureBlock | None = None + #: Other claims found in the input that were NOT assessed; else empty. + more_claims: list[str] = Field(default_factory=list) + #: Deprecated: ``failure.code`` on a failed row, with "nothing + #: checkable" spelled ``no_claim``; ``None`` on a completed row. + error_code: str | None = Field(default=None, json_schema_extra={"deprecated": True}) # Deprecated: always empty since 2026-09-12, when the ``ambiguous`` cause # that filled it was retired. Kept because the server still sends the key. candidate_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) - # Other claims found in the input that were NOT assessed; else empty. - identified_claims: list[str] = Field(default_factory=list) - # One sentence on what to send next. Set on every Error row and on a row - # with a non-empty ``identified_claims``; ``None`` on a plain verdict row. - hint: str | None = None + #: Deprecated: :attr:`more_claims`. + identified_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) + #: Deprecated: one sentence on what to send next. On a failed row it is + #: ``failure.hint``. The original response shape also set it on a row + #: with other claims found; the newer shape does not. + hint: str | None = Field(default=None, json_schema_extra={"deprecated": True}) + + @model_validator(mode="before") + @classmethod + @_reads_both("status", "failure", "more_claims") + def _read_both_shapes(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + out = _mirror(dict(data), "more_claims", "identified_claims") + status = out.get("status") + verdict = out.get("verdict") + if not status: + status = "failed" if verdict == "Error" else ("completed" if verdict else "") + out["status"] = status + if status == "failed": + # The original meaning of a row with no verdict. + if not verdict: + out["verdict"] = "Error" + if out.get("confidence") is None: + out["confidence"] = "low" + else: + if verdict is None: + out["verdict"] = "" + if out.get("confidence") is None: + out["confidence"] = "low" + failure = out.get("failure") + if isinstance(failure, dict): + code = failure.get("code", failure.get("failure_reason")) + out.setdefault("error_code", _old_code(code, "no_claim")) + out.setdefault("hint", failure.get("hint")) + elif failure is None and status == "failed" and "failure" not in data: + # The original shape: build the block from the row's own fields. + out["failure"] = {"code": _new_code(out.get("error_code") or ""), "hint": out.get("hint")} + return out + + +#: The ``AssessResponse.status`` values this release knows about. A +#: documentation constant, like ``ExtractStatus``: the field stays ``str``. +#: +#: - ``ok`` — at least one row has a verdict (a list may mix in failed rows). +#: - ``no_checkable_claim`` — the input, or every item, holds nothing that +#: can be checked. +#: - ``error`` — no row has a verdict, for another reason (see the rows). +AssessStatus = Literal["ok", "no_checkable_claim", "error"] class AssessResponse(_Lax): @@ -520,23 +854,32 @@ class AssessResponse(_Lax): found in the input — up to 20, at 1 credit each. A text that makes more claims than one call checks gets its most check-worthy 20 checked and the rest listed in ``more_claims``, unchecked and free: send them back with - ``assess(claims=...)``, 20 a call, to check them. ``error`` is set when - the input holds no checkable claim. + ``assess(claims=...)``, 20 a call, to check them. When the input holds no + checkable claim, ``claims`` is empty, ``status`` is + ``"no_checkable_claim"`` and ``failure`` says why. List form (``assess(claims=[...])``): exactly one entry per item sent, - in the order sent. An item that could not be given a verdict is an - ``"Error"`` row in position (see ``AssessClaim``), never a missing one; - the top-level ``error`` stays ``None``. - - When ``claims`` is empty (single form), ``error_code`` is ``'no_claim'``: - the input holds no checkable claim (a vague input is assessed on its - most likely reading instead). It defaults empty, so older servers that - don't send it degrade to the plain ``error`` message. + in the order sent. An item that could not be given a verdict is a + ``"failed"`` row in position (see ``AssessClaim``), never a missing one; + the top-level ``failure`` stays ``None``. + + ``status`` (see ``AssessStatus``) sums the call up: ``ok``, + ``no_checkable_claim`` or ``error``. Computed from the rows when a server + does not send it. + + Deprecated, kept with their original meaning: ``error`` is the sentence + (``failure.detail``) and ``error_code`` is ``'no_claim'`` when the + single form found no checkable claim; both are empty otherwise. """ + status: str = "" claims: list[AssessClaim] = Field(default_factory=list) - error: str | None = None - error_code: str = "" # '' | 'no_claim' + #: Why the single form has no rows; ``None`` otherwise. + failure: FailureBlock | None = None + #: Deprecated: ``failure.detail``. + error: str | None = Field(default=None, json_schema_extra={"deprecated": True}) + #: Deprecated: ``'no_claim'`` when ``failure`` says nothing was checkable. + error_code: str = Field(default="", json_schema_extra={"deprecated": True}) # '' | 'no_claim' # Deprecated: always empty since 2026-09-12. Kept because the server # still sends the key. candidate_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) @@ -544,12 +887,65 @@ class AssessResponse(_Lax): # first; ``[]`` otherwise, on the list form, and from older servers. more_claims: list[str] = Field(default_factory=list) + @model_validator(mode="before") + @classmethod + @_reads_both("status", "failure") + def _read_both_shapes(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + out = dict(data) + failure = out.get("failure") + if isinstance(failure, dict): + code = failure.get("code", failure.get("failure_reason")) + out.setdefault("error", failure.get("detail")) + out.setdefault("error_code", _old_code(code, "no_claim") or "") + elif failure is None and "failure" not in data and (out.get("error") or out.get("error_code")): + out["failure"] = {"code": _new_code(out.get("error_code") or ""), "detail": out.get("error")} + if out.get("error_code") is None: + out["error_code"] = "" + if not out.get("status"): + out["status"] = _assess_status(out) + return out + + +def _assess_status(body: dict[str, Any]) -> str: + """``AssessResponse.status`` for a body that does not carry it.""" + rows = [r for r in body.get("claims") or [] if isinstance(r, dict)] + failed = [r for r in rows if r.get("status") == "failed" or r.get("verdict") in ("Error", None, "")] + if rows and len(failed) < len(rows): + return "ok" + + def _code(block: Any, fallback: Any) -> Any: + if isinstance(block, dict): + return block.get("code", block.get("failure_reason")) + return fallback + + if not rows: + code = _code(body.get("failure"), body.get("error_code")) + return NO_CHECKABLE_CLAIM if _new_code(code) == NO_CHECKABLE_CLAIM else "error" + codes = {_new_code(_code(r.get("failure"), r.get("error_code"))) for r in rows} + return NO_CHECKABLE_CLAIM if codes == {NO_CHECKABLE_CLAIM} else "error" + class TaskAccepted(_Lax): - """Returned by ``POST /verify`` and per item of ``POST /verify/batch``.""" + """Returned by ``POST /verify`` and per item of ``POST /verify/batch`` + and ``POST /verify/{task_id}/select``. + + ``claim`` is the item's claim on a batch or select receipt (``""`` on a + single ``verify`` receipt). ``claim_text`` is its older name, the same + string (deprecated; either response shape fills both). + """ task_id: str = "" - claim_text: str = "" + claim: str = "" + #: Deprecated: the same string as :attr:`claim`. + claim_text: str = Field(default="", json_schema_extra={"deprecated": True}) + + @model_validator(mode="before") + @classmethod + @_reads_both("claim") + def _read_both_shapes(cls, data: Any) -> Any: + return _mirror(data, "claim", "claim_text") if isinstance(data, dict) else data class BatchAccepted(_Lax): @@ -643,14 +1039,23 @@ class TaskStatus(_Lax): # the JSON schema only, so reading them does not warn. candidates: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) similar_claims: list[SimilarVerification] = Field(default_factory=list, json_schema_extra={"deprecated": True}) - # failure branches. The server's failed response is - # ``{"status": "failed", "error": "..."}`` — ``error`` is the live wire - # field. ``failure_reason`` / ``failure_detail`` are kept for forward/back - # compatibility and other channels; read precedence is - # ``error or failure_detail or failure_reason``. - error: str = "" - failure_reason: str = "" - failure_detail: str = "" + #: On ``failed``: why. ``failure.code`` is the specific cause (an open + #: set, e.g. ``research_empty``, ``no_checkable_claim``), ``failure.detail`` + #: one sentence on what happened, ``failure.failure_class`` the closed + #: :data:`FailureClass`, ``failure.retryable`` whether resending the same + #: claim can help, ``failure.hint`` what to send instead (when the server + #: has one) and ``failure.docs_url`` where the class is explained. Filled + #: from either response shape; ``None`` on every other status. + failure: FailureBlock | None = None + # The original failure fields, deprecated and kept with their original + # meaning whichever response shape arrived: ``error`` is the sentence, + # ``failure_reason`` the cause (``not_a_claim`` where ``failure.code`` + # reads ``no_checkable_claim``), and ``failure_class`` / ``retryable`` / + # ``docs_url`` / ``hint`` the same values as on ``failure``. + # ``failure_detail`` is never sent by the API; it stays for old code. + error: str = Field(default="", json_schema_extra={"deprecated": True}) + failure_reason: str = Field(default="", json_schema_extra={"deprecated": True}) + failure_detail: str = Field(default="", json_schema_extra={"deprecated": True}) # WHY it failed — the closed set is ``FailureClass`` (import it for # exhaustive matching). The annotation stays ``str`` on purpose: a # ``Literal`` here would make an unknown class the server adds later a @@ -662,6 +1067,43 @@ class TaskStatus(_Lax): # Where this ``failure_class`` is explained. ``""`` from older servers. docs_url: str = "" + @model_validator(mode="before") + @classmethod + @_reads_both("failure") + def _read_both_shapes(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + out = dict(data) + failure = out.get("failure") + if isinstance(failure, dict): + # The newer shape: the original top-level fields from the block. + code = failure.get("code", failure.get("failure_reason")) + for key, value in ( + ("error", failure.get("detail")), + ("failure_reason", _old_code(code, "not_a_claim")), + ("failure_class", failure.get("failure_class")), + ("retryable", failure.get("retryable")), + ("docs_url", failure.get("docs_url")), + ("hint", failure.get("hint")), + ): + if out.get(key) is None: + out[key] = value + elif out.get("status") == "failed" and failure is None: + # The original shape: the block from the top-level fields. + out["failure"] = { + "code": _new_code(out.get("failure_reason") or ""), + "detail": out.get("error") or out.get("failure_detail") or None, + "failure_class": out.get("failure_class") or "", + "retryable": out.get("retryable") if isinstance(out.get("retryable"), bool) else None, + "hint": out.get("hint") or None, + "docs_url": out.get("docs_url") or "", + } + # ``None`` reads as the field's empty value, never as a validation error. + for key in ("error", "failure_reason", "failure_detail", "failure_class", "docs_url", "hint", "reason"): + if key in out and out[key] is None: + out[key] = "" + return out + class BatchItemResult(_Lax): """Per-item outcome from :meth:`Lenz.verify_batch_and_wait`. @@ -680,11 +1122,19 @@ class BatchItemResult(_Lax): """ task_id: str = "" - claim_text: str = "" + claim: str = "" + #: Deprecated: the same string as :attr:`claim`. + claim_text: str = Field(default="", json_schema_extra={"deprecated": True}) status: Literal["completed", "needs_input", "failed", "timeout"] verification: Verification | None = None status_detail: TaskStatus | None = None + @model_validator(mode="before") + @classmethod + @_reads_both("claim") + def _read_both_names(cls, data: Any) -> Any: + return _mirror(data, "claim", "claim_text") if isinstance(data, dict) else data + class UsageCredits(_Lax): """The account's credit balance — the one pool every capability spends. @@ -696,7 +1146,7 @@ class UsageCredits(_Lax): resets at ``resets_at``, and non-expiring ``extra`` credits from grants and top-ups, spent only once the allowance is gone. ``remaining`` covers both and is what a call is checked against. ``bonus`` is the deprecated old - name of ``extra``, the same number, removed on 2026-11-29. + name of ``extra``, the same number, kept for existing code. Servers predating the credit pool (before 2026-08-29) don't send this block at all, and it then reads as all-zero — check ``usage.credits.total`` @@ -709,14 +1159,14 @@ class UsageCredits(_Lax): #: The non-expiring part of ``remaining``: credits from grants and top-ups, #: spent only once the monthly allowance is gone. extra: int = 0 - #: **Deprecated** old name of :attr:`extra`, the same number, removed on - #: 2026-11-29. Reading it emits a ``DeprecationWarning``; it stays in - #: ``model_dump()`` output (unwarned) for as long as the server sends it. + #: **Deprecated** old name of :attr:`extra`, the same number, kept for + #: existing code. Reading it emits a ``DeprecationWarning``; it stays in + #: ``model_dump()`` output (unwarned), filled from ``extra`` when the + #: server does not send it. bonus: int = Field( default=0, deprecated=( - "UsageCredits.bonus is deprecated and will be removed on 2026-11-29; " - "use `extra` — the same number, the non-expiring part of the balance." + "UsageCredits.bonus is deprecated; use `extra` — the same number, the non-expiring part of the balance." ), ) resets_at: str | None = None @@ -727,8 +1177,8 @@ def _mirror_extra_and_bonus(cls, data: Any) -> Any: """Keep ``extra`` and its deprecated old name in step, in both directions. A server that has not started sending ``extra`` sends only ``bonus``; - a server after the 2026-11-29 removal sends only ``extra``. Mirroring - here means both attributes read correctly either way. + the newer response shape sends only ``extra``. Mirroring here means + both attributes read correctly either way. """ if not isinstance(data, dict): return data @@ -743,9 +1193,11 @@ def _mirror_extra_and_bonus(cls, data: Any) -> Any: class UsageCapacity(_Lax): """DEPRECATED. One capability's share of the pool, in that capability's unit. - **Removed 2026-11-29**, together with the per-block ``credits`` alias. - Read :attr:`Usage.credits` and :attr:`Usage.costs` and do the division — - it is the same one this block does:: + Deprecated, together with the per-block ``credits`` alias, and kept for + existing code: the newer response shape does not send these blocks, and + the SDK then computes them from :attr:`Usage.credits` and + :attr:`Usage.costs`. Read those two and do the division yourself — it is + the same one this block does:: remaining = u.credits.remaining // u.costs[capability] total = u.credits.total // u.costs[capability] @@ -778,7 +1230,7 @@ class UsageCapacity(_Lax): quota_total: int = 0 quota_remaining: int = 0 bonus: int = 0 - #: **Deprecated** alias of :attr:`bonus`, removed on 2026-11-29. It never + #: **Deprecated** alias of :attr:`bonus`, kept for existing code. It never #: meant the credit pool — before the pool existed it meant this #: capability's one-off top-up balance, which is exactly what ``bonus`` #: reports. Reading it emits a ``DeprecationWarning``; it stays in @@ -786,7 +1238,7 @@ class UsageCapacity(_Lax): credits: int = Field( default=0, deprecated=( - "UsageCapacity.credits is deprecated and will be removed on 2026-11-29; " + "UsageCapacity.credits is deprecated; " "use `bonus` — the same number, this capability's non-expiring top-up " "balance. The credit pool itself is `Usage.credits`." ), @@ -798,8 +1250,8 @@ class UsageCapacity(_Lax): def _mirror_bonus_and_credits(cls, data: Any) -> Any: """Keep ``bonus`` and its deprecated alias in step, in both directions. - A server predating the credit pool sends only ``credits``; a server - after the 2026-11-29 removal sends only ``bonus``. Mirroring here means + A server predating the credit pool sends only ``credits``; a block the + SDK computed has only ``bonus``. Mirroring here means both attributes read correctly either way, so the SDK never depends on which side of an API deploy it is talking to. """ @@ -850,7 +1302,9 @@ class Usage(_Lax): #: comparing against it will break on a rename that ought to be free. #: Empty on servers predating this field — fall back to :attr:`plan`. plan_label: str = "" - quota_resets_at: str | None = None + #: Deprecated: the same time as ``credits.resets_at``, which it is + #: filled from when the server does not send it. + quota_resets_at: str | None = Field(default=None, json_schema_extra={"deprecated": True}) #: The credit balance — the authoritative number. Empty on older servers. credits: UsageCredits = Field(default_factory=UsageCredits) #: Credits per call, keyed by CAPABILITY, at its default price: @@ -886,14 +1340,17 @@ class Usage(_Lax): #: read ``standard`` on a ``low`` request — the echo describes the #: evidence, the charge follows the request. cost_options: dict[str, dict[str, dict[str, int]]] = Field(default_factory=dict) - #: DEPRECATED — removed 2026-11-29. Derive from :attr:`credits` and + #: DEPRECATED, kept for existing code. Derive from :attr:`credits` and #: :attr:`costs` instead:: #: #: left = u.credits.remaining // u.costs["verify"] + #: + #: Computed that way when the server does not send the block (the newer + #: response shape does not). verify: UsageCapacity = Field(default_factory=UsageCapacity) - #: DEPRECATED — removed 2026-11-29. See :attr:`verify`. + #: DEPRECATED, kept for existing code. See :attr:`verify`. ask: UsageCapacity = Field(default_factory=UsageCapacity) - #: DEPRECATED — removed 2026-11-29. See :attr:`verify`. + #: DEPRECATED, kept for existing code. See :attr:`verify`. assess: UsageCapacity = Field(default_factory=UsageCapacity) extract: UsageExtract = Field(default_factory=UsageExtract) # Whether this key has a webhook signing secret provisioned. ``POST /verify`` @@ -903,6 +1360,49 @@ class Usage(_Lax): # Defaults to ``False`` on servers predating this field. has_webhook_secret: bool = False + @model_validator(mode="before") + @classmethod + @_reads_both(always_hide=True) + def _read_both_shapes(cls, data: Any) -> Any: + """Compute the deprecated blocks the newer response shape leaves out. + + Each per-capability block is the credit pool divided by that + capability's price, exactly as the server computed it; it is filled + only when the server sent the pool and the price but not the block. + """ + if not isinstance(data, dict): + return data + credits, costs = data.get("credits"), data.get("costs") + if not isinstance(credits, dict): + return data + out = dict(data) + if "quota_resets_at" not in out: + out["quota_resets_at"] = credits.get("resets_at") + if not isinstance(costs, dict): + return out + + def _int(value: Any) -> int: + return value if isinstance(value, int) and not isinstance(value, bool) else 0 + + total, remaining, extra = ( + _int(credits.get("total")), + _int(credits.get("remaining")), + _int(credits.get("extra", credits.get("bonus"))), + ) + for capability in ("verify", "ask", "assess"): + cost = _int(costs.get(capability)) + if capability in out or cost <= 0: + continue + quota_total, left = total // cost, remaining // cost + out[capability] = { + "quota_used": quota_total - left, + "quota_total": quota_total, + "quota_remaining": left, + "bonus": extra // cost, + "remaining": left, + } + return out + class AskMessage(_Lax): """One message in an ``/ask`` conversation thread.""" @@ -970,24 +1470,6 @@ class ReviewStarted(_Lax): status: str = "queued" -class FailureBlock(_Lax): - """Why a review, or one claim's work inside it, failed. - - The same fields a failed ``GET /verify/status`` carries: ``failure_reason`` - is the specific cause (an open set, e.g. ``no_claim``, - ``insufficient_credits``, ``timeout``), ``failure_class`` the closed - :data:`FailureClass`, ``retryable`` whether resending the same request can - help, ``hint`` one sentence on what to do next and ``docs_url`` where the - class is explained. - """ - - failure_reason: str | None = "" - failure_class: str | None = "" - retryable: bool | None = None - hint: str | None = None - docs_url: str | None = "" - - class EscalationPolicy(_Lax): """Which quick-checked claims get a deep check, as the review RESOLVED it. @@ -1055,11 +1537,19 @@ class ReviewSummary(_Lax): The ``citation*`` counts are ``None`` (``citation_issues`` 0) on a review that did not ask for the citation check.""" + #: How many claims the draft holds. ``None`` until the draft is read, + #: and from the original response shape, which does not send it. + claims_found: int | None = None claims_selected: int | None = None #: The resolved ``max_assessments``. claim_limit: int = 20 - #: The draft held at least ``claim_limit`` claims: more MAY exist. - claim_limit_reached: bool | None = None + #: Some of the draft's claims were left out (more than ``claim_limit``): + #: they are in ``more_claims``. From the original response shape it is + #: read off ``more_claims`` once the draft is read. + claim_limit_exceeded: bool | None = None + #: Deprecated: the draft held at least ``claim_limit`` claims, so more + #: MAY exist. Read :attr:`claim_limit_exceeded`, which says whether they do. + claim_limit_reached: bool | None = Field(default=None, json_schema_extra={"deprecated": True}) #: The text was cut at 50,000 characters. input_truncated: bool = False assessments: ReviewAssessmentCounts | None = None @@ -1071,8 +1561,10 @@ class ReviewSummary(_Lax): citations_selected: int | None = None #: The resolved ``max_citations``. citation_limit: int | None = None - #: ``citations_found`` is over ``citation_limit``. - citation_limit_reached: bool | None = None + #: ``citations_found`` is over ``citation_limit``: some were left out. + citation_limit_exceeded: bool | None = None + #: Deprecated: the same value as :attr:`citation_limit_exceeded`. + citation_limit_reached: bool | None = Field(default=None, json_schema_extra={"deprecated": True}) citation_checks: ReviewCitationCheckCounts | None = None #: ``len(citation_issues)``. citation_issues: int = 0 @@ -1081,6 +1573,18 @@ class ReviewSummary(_Lax): #: An open set. citations_skipped: str | None = None + @model_validator(mode="before") + @classmethod + @_reads_both("claims_found", "claim_limit_exceeded", "citation_limit_exceeded") + def _read_both_shapes(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + out = _mirror(dict(data), "citation_limit_exceeded", "citation_limit_reached") + if "claim_limit_reached" not in out and "claims_found" in out: + found, limit = out.get("claims_found"), out.get("claim_limit", 20) + out["claim_limit_reached"] = found >= limit if isinstance(found, int) and isinstance(limit, int) else None + return out + class ReviewCredits(_Lax): """``charged`` is the net credits the review cost the account, its @@ -1104,8 +1608,15 @@ class ReviewResult(_Lax): class ReviewAssessment(_Lax): """A claim's quick check. ``status``: ``pending`` | ``running`` | ``completed`` | ``failed``. On ``completed`` the fields mean what they - mean on an ``/assess`` row; on ``failed`` see ``error_code`` (an open - set, as on ``/assess``), ``hint`` and ``failure``.""" + mean on an ``/assess`` row; on ``failed`` see ``failure`` (its ``code`` + an open set, as on ``/assess``). ``more_claims`` lists other claims + found in the passage that were not checked. + + Deprecated, kept with their original meaning: ``error_code`` is + ``failure.code`` on a failed row (``no_claim`` where the code reads + ``no_checkable_claim``), ``identified_claims`` is ``more_claims``, and + ``hint`` is the row's own hint from the original response shape + (``None`` from the newer one; read ``failure.hint``).""" status: str = "" verdict: str | None = None @@ -1113,9 +1624,13 @@ class ReviewAssessment(_Lax): rationale: str | None = None dissent: str | None = None verification_url: str | None = None - error_code: str | None = None - identified_claims: list[str] = Field(default_factory=list) - hint: str | None = None + more_claims: list[str] = Field(default_factory=list) + #: Deprecated: ``failure.code`` on a failed row. + error_code: str | None = Field(default=None, json_schema_extra={"deprecated": True}) + #: Deprecated: :attr:`more_claims`. + identified_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) + #: Deprecated. See the class docstring. + hint: str | None = Field(default=None, json_schema_extra={"deprecated": True}) #: With ``suggest_edits=True``: the claim with its wrong part corrected, #: from the quick check's reasoning, when it found the claim "False" or #: "Mostly False" with high confidence. ``None`` otherwise, and from @@ -1124,6 +1639,18 @@ class ReviewAssessment(_Lax): suggested_rewrite: str | None = None failure: FailureBlock | None = None + @model_validator(mode="before") + @classmethod + @_reads_both("more_claims") + def _read_both_shapes(cls, data: Any) -> Any: + if not isinstance(data, dict): + return data + out = _mirror(dict(data), "more_claims", "identified_claims") + failure = out.get("failure") + if "error_code" not in out and isinstance(failure, dict): + out["error_code"] = _old_code(failure.get("code", failure.get("failure_reason")), "no_claim") + return out + class ReviewEntity(_Lax): """An entity the deep check found in the claim. ``qid`` is its Wikidata @@ -1164,11 +1691,20 @@ class ReviewVerification(_Lax): suggested_rewrite: str | None = None warnings: list[str] = Field(default_factory=list) created_at: str | None = None - modified_at: str | None = None + #: See ``Verification.completed_at``. + completed_at: str | None = None + #: Deprecated. See ``Verification.modified_at``. + modified_at: str | None = Field(default=None, json_schema_extra={"deprecated": True}) verification_url: str | None = None url: str | None = None failure: FailureBlock | None = None + @model_validator(mode="before") + @classmethod + @_reads_both("completed_at") + def _read_both_shapes(cls, data: Any) -> Any: + return _with_completion_times(data) + class SuggestedEdit(_Lax): """One replacement in the draft: the span ``start``..``end`` of the @@ -1469,10 +2005,19 @@ class CitecheckSummary(_Lax): citations_found: int | None = None citations_selected: int | None = None citation_limit: int | None = None - citation_limit_reached: bool | None = None + #: ``citations_found`` is over ``citation_limit``: some were left out. + citation_limit_exceeded: bool | None = None + #: Deprecated: the same value as :attr:`citation_limit_exceeded`. + citation_limit_reached: bool | None = Field(default=None, json_schema_extra={"deprecated": True}) citation_checks: ReviewCitationCheckCounts | None = None citation_issues: int = 0 + @model_validator(mode="before") + @classmethod + @_reads_both("citation_limit_exceeded") + def _read_both_shapes(cls, data: Any) -> Any: + return _mirror(data, "citation_limit_exceeded", "citation_limit_reached") if isinstance(data, dict) else data + class Citecheck(_Lax): """``GET /citechecks/{citecheck_id}``: a citation check as it stands. @@ -1548,6 +2093,15 @@ class ReviewEnvelope(_Lax): more_citations: list[ReviewMoreCitation] | None = None failure: FailureBlock | None = None + @model_validator(mode="after") + def _claim_limit_exceeded_from_more_claims(self) -> ReviewEnvelope: + """The original shape says only that the limit was REACHED; whether + claims were left out is whether ``more_claims`` lists any.""" + summary = self.summary + if summary.claim_limit_exceeded is None and self.more_claims is not None: + summary.claim_limit_exceeded = bool(self.more_claims) + return self + class ReviewFull(ReviewEnvelope): """``GET /reviews/{review_id}``: the envelope plus every claim.""" @@ -1564,11 +2118,13 @@ class ReviewIssues(ReviewEnvelope): __all__ = [ + "NO_CHECKABLE_CLAIM", "AskHistory", "AskMessage", "AskReply", "AssessClaim", "AssessResponse", + "AssessStatus", "Assessment", "Audit", "BatchAccepted", @@ -1584,6 +2140,7 @@ class ReviewIssues(ReviewEnvelope): "Escalation", "EscalationPolicy", "ExtractStatus", + "ExtractedClaim", "ExtractedClaims", "ExtractedEntity", "FailureBlock", diff --git a/src/lenz_io/webhooks.py b/src/lenz_io/webhooks.py index 89eb1d9..c88741b 100644 --- a/src/lenz_io/webhooks.py +++ b/src/lenz_io/webhooks.py @@ -35,7 +35,15 @@ from typing import Any from .errors import LenzWebhookSignatureError -from .models import Citecheck, ReviewFull +from .models import ( + CandidateClaim, + Citecheck, + FailureBlock, + ReviewFull, + _new_code, + _old_code, + _with_completion_times, +) SIGNATURE_HEADER = "X-Lenz-Signature" SIGNATURE_PREFIX = "sha256=" @@ -87,11 +95,24 @@ def verify_signature(raw_body: bytes, signature: str, secret: str) -> bool: # ── Typed events ───────────────────────────────────────────────────────── +# +# Two payload shapes reach the same events. The original one is flat for +# ``verification.*`` (``result``, ``needs_input``, ``error`` at the top) and +# nested for ``review.*`` / ``citecheck.*``. The newer one is one envelope for +# every event: ``event``, ``event_id``, the work's id, ``status``, and the body +# polling returns under the work's kind (``verification``, ``review``, +# ``citecheck``). Every attribute below is filled from either shape, and the +# original attributes keep their original meaning. @dataclass class WebhookEvent: - """Base class. Use ``isinstance`` to discriminate the union.""" + """Base class. Use ``isinstance`` to discriminate the union. + + ``event_id`` is the same on every delivery attempt of one event, while + ``attempt`` counts up: deduplicate on it. ``""`` when a payload does not + carry it (the original ``verification.*`` and ``certificate.*`` shape). + """ event: str task_id: str @@ -101,11 +122,18 @@ class WebhookEvent: batch_id: str | None = None status: str = "" raw: dict[str, Any] = field(default_factory=dict, repr=False) + # Keyword-only, so positional construction of every event keeps its order. + event_id: str = field(default="", kw_only=True) @dataclass class VerificationCompleted(WebhookEvent): - """``event=verification.completed`` — the pipeline produced a verdict.""" + """``event=verification.completed`` — the pipeline produced a verdict. + + ``result`` is the verification as a dict, the same body + ``verifications.get`` returns, as sent; from the newer payload shape, + which sends ``completed_at``, the deprecated ``modified_at`` is added. + """ result: dict[str, Any] = field(default_factory=dict) @@ -114,15 +142,22 @@ class VerificationCompleted(WebhookEvent): class VerificationFailed(WebhookEvent): """``event=verification.failed`` — the pipeline terminated without a verdict. - ``failure_class`` is WHY (closed set — ``upstream_unavailable`` | - ``insufficient_evidence`` | ``invalid_input`` | ``cancelled`` | - ``internal``); ``retryable`` is the derived signal (true iff - ``upstream_unavailable``). Both default when an older server omits them. + ``failure`` says why: ``failure.code`` is the cause (an open set), + ``failure.detail`` one sentence on what happened, ``failure.failure_class`` + the closed set (``upstream_unavailable`` | ``insufficient_evidence`` | + ``invalid_input`` | ``cancelled`` | ``internal``) and ``failure.retryable`` + the derived signal (true iff ``upstream_unavailable``). + + The original attributes keep their meaning: ``error`` is the cause code + (``not_a_claim`` where ``failure.code`` reads ``no_checkable_claim``), + and ``failure_class`` / ``retryable`` repeat the block's. They default when + an older server omits them. """ error: str = "" failure_class: str = "" retryable: bool | None = None + failure: FailureBlock | None = None @dataclass @@ -133,13 +168,18 @@ class VerificationNeedsInput(WebhookEvent): pipeline run produces a ``verification.completed`` (or another ``needs_input``) event. - ``hint`` is one sentence on what was unclear and how to resolve it - (``needs_input["hint"]`` on the wire); ``""`` when an older server omits - it. + ``reason`` is why (``multi_claim``), ``claims`` the options to pick from + (each with ``claim`` and ``domain``) and ``hint`` one sentence on what was + unclear and how to resolve it (``""`` when an older server omits it). + ``needs_input`` is the original dict, ``{"reason", "claims", "hint"}``, + whose options carry the claim as ``text``: as sent, or built from the + newer payload shape. """ needs_input: dict[str, Any] = field(default_factory=dict) hint: str = "" + reason: str = "" + claims: list[CandidateClaim] = field(default_factory=list) @dataclass @@ -171,8 +211,9 @@ class ReviewEvent(WebhookEvent): ``review.issues``. Deduplicate on ``event_id``: it is the same on every delivery attempt of - one event, while ``attempt`` counts up. ``task_id`` identifies the - delivery and cannot be polled on ``/verify/status``. The deep checks a + one event, while ``attempt`` counts up. ``task_id`` (deprecated) + identifies the delivery and cannot be polled on ``/verify/status``; a + payload that does not carry it reads ``event_id`` there. The deep checks a review runs send no ``verification.*`` events of their own. """ @@ -189,8 +230,9 @@ class CitecheckEvent(WebhookEvent): ``citecheck`` is the final check (the same body ``get_citecheck`` returns), or ``None`` if it could not be parsed (``raw["citecheck"]`` still has it). Deduplicate on ``event_id``: it is the same on every - delivery attempt of one event. ``task_id`` identifies the delivery and - cannot be polled on ``/verify/status``. + delivery attempt of one event. ``task_id`` (deprecated) identifies the + delivery and cannot be polled on ``/verify/status``; a payload that does + not carry it reads ``event_id`` there. """ event_id: str = "" @@ -198,120 +240,127 @@ class CitecheckEvent(WebhookEvent): citecheck: Citecheck | None = None +def _dict(value: Any) -> dict[str, Any]: + return value if isinstance(value, dict) else {} + + +def _opt_id(*values: Any) -> str | None: + for value in values: + if value: + return str(value) + return None + + +def _legacy_needs_input(payload: dict[str, Any], body: dict[str, Any]) -> dict[str, Any]: + """The original ``needs_input`` dict: as sent, or built from the newer + envelope's polled body (each option carrying the claim as ``text``).""" + if isinstance(payload.get("needs_input"), dict): + return payload["needs_input"] # type: ignore[no-any-return] + claims = [] + for option in body.get("claims") or []: + if isinstance(option, dict): + claims.append({"text": option.get("claim", option.get("text")), "domain": option.get("domain", "")}) + out: dict[str, Any] = {"reason": body.get("reason", "")} + out["claims"] = claims + out["hint"] = body.get("hint", "") + return out + + def _build_event(payload: dict[str, Any]) -> WebhookEvent: """Discriminate on ``event`` and return the right typed dataclass.""" event = str(payload.get("event") or "") - task_id = str(payload.get("task_id") or "") + # The newer envelope nests the polled body under the work's kind. + body = _dict(payload.get("verification")) + result = _dict(payload.get("result")) or _dict(body.get("result")) + event_id = str(payload.get("event_id") or "") + task_id = str(payload.get("task_id") or body.get("task_id") or "") try: attempt = int(payload.get("attempt") or 1) except (TypeError, ValueError): attempt = 1 delivered_at = str(payload.get("delivered_at") or "") - verification_id = str(payload["verification_id"]) if payload.get("verification_id") else None - batch_id = str(payload["batch_id"]) if payload.get("batch_id") else None - status = str(payload.get("status") or "") + verification_id = _opt_id(payload.get("verification_id"), result.get("verification_id")) + batch_id = _opt_id(payload.get("batch_id"), body.get("batch_id")) + status = str(payload.get("status") or body.get("status") or "") + common: dict[str, Any] = { + "event": event, + "task_id": task_id, + "attempt": attempt, + "delivered_at": delivered_at, + "verification_id": verification_id, + "batch_id": batch_id, + "status": status, + "raw": payload, + "event_id": event_id, + } if event == "verification.completed": - return VerificationCompleted( - event=event, - task_id=task_id, - attempt=attempt, - delivered_at=delivered_at, - verification_id=verification_id, - batch_id=batch_id, - status=status, - raw=payload, - result=payload.get("result") or {}, - ) + if result and "modified_at" not in result: + # The newer shape: add the original ``modified_at`` (computed), + # leaving an original-shape result exactly as sent. + result = _with_completion_times(result) + return VerificationCompleted(**common, result=result) if event == "verification.failed": + block = _dict(body.get("failure")) or _dict(payload.get("failure")) + failure = FailureBlock.model_validate(block) if block else None + legacy_error = payload.get("error") + error = legacy_error if isinstance(legacy_error, str) and legacy_error else "" + if not error and failure is not None: + error = str(_old_code(failure.code, "not_a_claim") or "") + failure_class = payload.get("failure_class") or (failure.failure_class if failure else "") or "" + retryable = payload.get("retryable") + if not isinstance(retryable, bool): + retryable = failure.retryable if failure is not None else None + if failure is None and (error or failure_class): + # The original shape: the block from the flat fields. + failure = FailureBlock.model_validate( + {"code": _new_code(error), "failure_class": failure_class, "retryable": retryable} + ) return VerificationFailed( - event=event, - task_id=task_id, - attempt=attempt, - delivered_at=delivered_at, - verification_id=verification_id, - batch_id=batch_id, - status=status, - raw=payload, - error=str(payload.get("error") or ""), - failure_class=str(payload.get("failure_class") or ""), - retryable=payload.get("retryable") if isinstance(payload.get("retryable"), bool) else None, + **common, + error=error, + failure_class=str(failure_class), + retryable=retryable if isinstance(retryable, bool) else None, + failure=failure, ) if event == "verification.needs_input": - needs_input = payload.get("needs_input") or {} + needs_input = _legacy_needs_input(payload, body) return VerificationNeedsInput( - event=event, - task_id=task_id, - attempt=attempt, - delivered_at=delivered_at, - verification_id=verification_id, - batch_id=batch_id, - status=status, - raw=payload, + **common, needs_input=needs_input, - hint=str(needs_input.get("hint") or "") if isinstance(needs_input, dict) else "", + hint=str(needs_input.get("hint") or ""), + reason=str(needs_input.get("reason") or ""), + claims=[CandidateClaim.model_validate(c) for c in needs_input.get("claims") or [] if isinstance(c, dict)], ) if event == "certificate.timestamped": - return CertificateTimestamped( - event=event, - task_id=task_id, - attempt=attempt, - delivered_at=delivered_at, - verification_id=verification_id, - batch_id=batch_id, - status=status, - raw=payload, - coverage=payload.get("coverage") or {}, - ) + coverage = _dict(payload.get("coverage")) or _dict(body.get("coverage")) or _dict(result.get("coverage")) + return CertificateTimestamped(**common, coverage=coverage) if event in ("review.completed", "review.failed"): - body = payload.get("review") + review_body = payload.get("review") try: - review = ReviewFull.model_validate(body) if isinstance(body, dict) else None + review = ReviewFull.model_validate(review_body) if isinstance(review_body, dict) else None except ValueError: review = None + common["task_id"] = task_id or event_id return ReviewEvent( - event=event, - task_id=task_id, - attempt=attempt, - delivered_at=delivered_at, - verification_id=verification_id, - batch_id=batch_id, - status=status, - raw=payload, - event_id=str(payload.get("event_id") or ""), - review_id=str(payload.get("review_id") or ""), + **common, + review_id=str(payload.get("review_id") or _dict(review_body).get("review_id") or ""), review=review, ) if event in ("citecheck.completed", "citecheck.failed"): - body = payload.get("citecheck") + check_body = payload.get("citecheck") try: - check = Citecheck.model_validate(body) if isinstance(body, dict) else None + check = Citecheck.model_validate(check_body) if isinstance(check_body, dict) else None except ValueError: check = None + common["task_id"] = task_id or event_id return CitecheckEvent( - event=event, - task_id=task_id, - attempt=attempt, - delivered_at=delivered_at, - verification_id=verification_id, - batch_id=batch_id, - status=status, - raw=payload, - event_id=str(payload.get("event_id") or ""), - citecheck_id=str(payload.get("citecheck_id") or ""), + **common, + citecheck_id=str(payload.get("citecheck_id") or _dict(check_body).get("citecheck_id") or ""), citecheck=check, ) # Unknown event type — return generic. Future-compatible: ignore events # you do not handle rather than failing the delivery. - return WebhookEvent( - event=event, - task_id=task_id, - attempt=attempt, - delivered_at=delivered_at, - verification_id=verification_id, - batch_id=batch_id, - status=status, - raw=payload, - ) + return WebhookEvent(**common) def parse_webhook(body: bytes | str | dict[str, Any]) -> WebhookEvent: diff --git a/tests/fixtures/parity/canonical/account__library_empty.json b/tests/fixtures/parity/canonical/account__library_empty.json new file mode 100644 index 0000000..b419316 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__library_empty.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [], + "total": 0, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/account__library_item_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/account__library_item_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..1045857 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__library_item_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "A library claim.", + "domain": "", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "completed_at": "2026-10-02T00:03:00.123456+00:00", + "language": "en" + } + ], + "total": 1, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/account__library_item_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/account__library_item_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..d4d580f --- /dev/null +++ b/tests/fixtures/parity/canonical/account__library_item_modified_at_same_day_hours_apart.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "A library claim.", + "domain": "", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "completed_at": "2026-10-01T20:00:00.123456+00:00", + "language": "en" + } + ], + "total": 1, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/account__library_items.json b/tests/fixtures/parity/canonical/account__library_items.json new file mode 100644 index 0000000..e810be9 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__library_items.json @@ -0,0 +1,60 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "Library claim 0.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", + "language": "en" + }, + { + "verification_id": "7c83247c", + "claim": "Library claim 1.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:28:00.123456+00:00", + "completed_at": "2026-10-01T09:28:00.123456+00:00", + "language": "en" + }, + { + "verification_id": "b79019e4", + "claim": "Library claim 2.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:42:00.123456+00:00", + "completed_at": "2026-10-01T09:42:00.123456+00:00", + "language": "en" + } + ], + "total": 3, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/account__library_no_match.json b/tests/fixtures/parity/canonical/account__library_no_match.json new file mode 100644 index 0000000..b419316 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__library_no_match.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [], + "total": 0, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/account__library_page_past_end.json b/tests/fixtures/parity/canonical/account__library_page_past_end.json new file mode 100644 index 0000000..86d64c7 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__library_page_past_end.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [], + "total": 1, + "page": 2, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/account__library_paginated_second_page.json b/tests/fixtures/parity/canonical/account__library_paginated_second_page.json new file mode 100644 index 0000000..ae61ec7 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__library_paginated_second_page.json @@ -0,0 +1,45 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "Paged claim 020.", + "domain": "", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", + "language": "en" + }, + { + "verification_id": "7c83247c", + "claim": "Paged claim 021.", + "domain": "", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:28:00.123456+00:00", + "completed_at": "2026-10-01T09:28:00.123456+00:00", + "language": "en" + } + ], + "total": 22, + "page": 2, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/account__me_usage_extra_credits.json b/tests/fixtures/parity/canonical/account__me_usage_extra_credits.json new file mode 100644 index 0000000..14ab818 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__me_usage_extra_credits.json @@ -0,0 +1,40 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "credits": { + "total": 350, + "used": 0, + "remaining": 350, + "extra": 250, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/canonical/account__me_usage_extra_only.json b/tests/fixtures/parity/canonical/account__me_usage_extra_only.json new file mode 100644 index 0000000..3b3e240 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__me_usage_extra_only.json @@ -0,0 +1,40 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "credits": { + "total": 137, + "used": 100, + "remaining": 37, + "extra": 37, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/canonical/account__me_usage_extract_calls.json b/tests/fixtures/parity/canonical/account__me_usage_extract_calls.json new file mode 100644 index 0000000..54303ab --- /dev/null +++ b/tests/fixtures/parity/canonical/account__me_usage_extract_calls.json @@ -0,0 +1,40 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "credits": { + "total": 100, + "used": 0, + "remaining": 100, + "extra": 0, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "extract": { + "calls_today": 7, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/canonical/account__me_usage_free.json b/tests/fixtures/parity/canonical/account__me_usage_free.json new file mode 100644 index 0000000..e9b9231 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__me_usage_free.json @@ -0,0 +1,40 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "credits": { + "total": 100, + "used": 0, + "remaining": 100, + "extra": 0, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/canonical/account__me_usage_free_partly_spent.json b/tests/fixtures/parity/canonical/account__me_usage_free_partly_spent.json new file mode 100644 index 0000000..d08a9ac --- /dev/null +++ b/tests/fixtures/parity/canonical/account__me_usage_free_partly_spent.json @@ -0,0 +1,40 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "credits": { + "total": 100, + "used": 17, + "remaining": 83, + "extra": 0, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/canonical/account__me_usage_plus.json b/tests/fixtures/parity/canonical/account__me_usage_plus.json new file mode 100644 index 0000000..4a255a9 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__me_usage_plus.json @@ -0,0 +1,40 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "plus", + "plan_label": "Plus", + "credits": { + "total": 500, + "used": 0, + "remaining": 500, + "extra": 0, + "resets_at": "2026-10-01T09:07:00.123456+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/canonical/account__me_usage_pro.json b/tests/fixtures/parity/canonical/account__me_usage_pro.json new file mode 100644 index 0000000..943f796 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__me_usage_pro.json @@ -0,0 +1,40 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "pro", + "plan_label": "Pro", + "credits": { + "total": 5000, + "used": 0, + "remaining": 5000, + "extra": 0, + "resets_at": "2026-10-01T09:07:00.123456+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/canonical/account__me_usage_pro_extra.json b/tests/fixtures/parity/canonical/account__me_usage_pro_extra.json new file mode 100644 index 0000000..8f8d482 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__me_usage_pro_extra.json @@ -0,0 +1,40 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "pro", + "plan_label": "Pro", + "credits": { + "total": 6000, + "used": 0, + "remaining": 6000, + "extra": 1000, + "resets_at": "2026-10-01T09:07:00.123456+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/canonical/account__me_usage_stale_quota_row.json b/tests/fixtures/parity/canonical/account__me_usage_stale_quota_row.json new file mode 100644 index 0000000..e9b9231 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__me_usage_stale_quota_row.json @@ -0,0 +1,40 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "credits": { + "total": 100, + "used": 0, + "remaining": 100, + "extra": 0, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/canonical/assess__401_no_key.json b/tests/fixtures/parity/canonical/assess__401_no_key.json new file mode 100644 index 0000000..1c3df51 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__401_no_key.json @@ -0,0 +1,12 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + } +} diff --git a/tests/fixtures/parity/canonical/assess__402_no_credits.json b/tests/fixtures/parity/canonical/assess__402_no_credits.json new file mode 100644 index 0000000..5e931cc --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__402_no_credits.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining /assess units.", + "code": "no_credits", + "docs_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/canonical/assess__422_blank_item.json b/tests/fixtures/parity/canonical/assess__422_blank_item.json new file mode 100644 index 0000000..db514d2 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__422_blank_item.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claims[1] is blank.", + "code": "blank_input", + "errors": [ + { + "loc": [ + "body", + "claims", + 1 + ], + "msg": "claims[1] is blank.", + "type": "blank_input" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/assess__422_blank_text.json b/tests/fixtures/parity/canonical/assess__422_blank_text.json new file mode 100644 index 0000000..a5a1062 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__422_blank_text.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claim is required.", + "code": "blank_input", + "errors": [ + { + "loc": [ + "body", + "claim" + ], + "msg": "claim is required.", + "type": "blank_input" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/assess__422_input_conflict.json b/tests/fixtures/parity/canonical/assess__422_input_conflict.json new file mode 100644 index 0000000..a46942a --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__422_input_conflict.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Send either `claim` (one text) or `claims` (a list of claims), not both.", + "code": "input_conflict", + "errors": [ + { + "loc": [ + "body", + "claims" + ], + "msg": "Send either `claim` (one text) or `claims` (a list of claims), not both.", + "type": "input_conflict" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/assess__422_item_too_long.json b/tests/fixtures/parity/canonical/assess__422_item_too_long.json new file mode 100644 index 0000000..137d44e --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__422_item_too_long.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claims[1] is 2001 characters; each claim may be at most 2000. Send a document to /extract first, then assess its claims.", + "code": "item_too_long", + "errors": [ + { + "loc": [ + "body", + "claims", + 1 + ], + "msg": "claims[1] is 2001 characters; each claim may be at most 2000. Send a document to /extract first, then assess its claims.", + "type": "item_too_long" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/assess__422_no_input_field.json b/tests/fixtures/parity/canonical/assess__422_no_input_field.json new file mode 100644 index 0000000..9136471 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__422_no_input_field.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claim: Field required", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/assess__422_too_many_items.json b/tests/fixtures/parity/canonical/assess__422_too_many_items.json new file mode 100644 index 0000000..3468b9e --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__422_too_many_items.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "At most 20 claims per call; got 21. Split the list.", + "code": "too_many_items", + "errors": [ + { + "loc": [ + "body", + "claims" + ], + "msg": "At most 20 claims per call; got 21. Split the list.", + "type": "too_many_items" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/assess__422_wrong_type_claim.json b/tests/fixtures/parity/canonical/assess__422_wrong_type_claim.json new file mode 100644 index 0000000..acbd190 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__422_wrong_type_claim.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claim: Input should be a valid string", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "claim" + ], + "msg": "Input should be a valid string", + "type": "string_type" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/assess__422_wrong_type_claims.json b/tests/fixtures/parity/canonical/assess__422_wrong_type_claims.json new file mode 100644 index 0000000..2b44c06 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__422_wrong_type_claims.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claims: Input should be a valid list", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "claims" + ], + "msg": "Input should be a valid list", + "type": "list_type" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/assess__502_framing_failed.json b/tests/fixtures/parity/canonical/assess__502_framing_failed.json new file mode 100644 index 0000000..e671a1e --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__502_framing_failed.json @@ -0,0 +1,12 @@ +{ + "status": 502, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Framing failed", + "code": "framing_failed" + } +} diff --git a/tests/fixtures/parity/canonical/assess__503_capacity.json b/tests/fixtures/parity/canonical/assess__503_capacity.json new file mode 100644 index 0000000..343e0e1 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__503_capacity.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "100", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": 100, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/assess__503_list_all_upstream_unavailable.json b/tests/fixtures/parity/canonical/assess__503_list_all_upstream_unavailable.json new file mode 100644 index 0000000..c19b99f --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__503_list_all_upstream_unavailable.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Our model providers are temporarily unavailable. Please retry shortly. Nothing was charged.", + "code": "upstream_unavailable", + "retry_after": 90, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/assess__503_upstream_unavailable.json b/tests/fixtures/parity/canonical/assess__503_upstream_unavailable.json new file mode 100644 index 0000000..3315806 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__503_upstream_unavailable.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Our model providers are temporarily unavailable. Please retry shortly.", + "code": "upstream_unavailable", + "retry_after": 90, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/assess__deep_tier_hit.json b/tests/fixtures/parity/canonical/assess__deep_tier_hit.json new file mode 100644 index 0000000..0a05b10 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__deep_tier_hit.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ok", + "claims": [ + { + "claim": "Water boils at 100C.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": "https://lenz.io/api/v1/verifications/f3436f50", + "rationale": "The claim is verified.", + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + } + ], + "failure": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__idempotency_body_mismatch.json b/tests/fixtures/parity/canonical/assess__idempotency_body_mismatch.json new file mode 100644 index 0000000..e20089e --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__idempotency_body_mismatch.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + } +} diff --git a/tests/fixtures/parity/canonical/assess__idempotency_first.json b/tests/fixtures/parity/canonical/assess__idempotency_first.json new file mode 100644 index 0000000..8c05be0 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__idempotency_first.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ok", + "claims": [ + { + "claim": "The Earth orbits the Sun.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + } + ], + "failure": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__idempotency_replay.json b/tests/fixtures/parity/canonical/assess__idempotency_replay.json new file mode 100644 index 0000000..8c05be0 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__idempotency_replay.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ok", + "claims": [ + { + "claim": "The Earth orbits the Sun.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + } + ], + "failure": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__list_all_error_rows.json b/tests/fixtures/parity/canonical/assess__list_all_error_rows.json new file mode 100644 index 0000000..75ced45 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__list_all_error_rows.json @@ -0,0 +1,55 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "no_checkable_claim", + "claims": [ + { + "claim": "hi", + "language": "en", + "status": "failed", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": { + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + } + }, + { + "claim": "hello", + "language": "en", + "status": "failed", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": { + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + } + } + ], + "failure": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__list_compound_item.json b/tests/fixtures/parity/canonical/assess__list_compound_item.json new file mode 100644 index 0000000..536868b --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__list_compound_item.json @@ -0,0 +1,44 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ok", + "claims": [ + { + "claim": "Primary claim.", + "language": "en", + "status": "completed", + "verdict": "Mostly False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [ + "Second claim.", + "Third claim." + ], + "failure": null + }, + { + "claim": "A plain claim.", + "language": "en", + "status": "completed", + "verdict": "Mostly False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + } + ], + "failure": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__list_mixed_rows.json b/tests/fixtures/parity/canonical/assess__list_mixed_rows.json new file mode 100644 index 0000000..5cec126 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__list_mixed_rows.json @@ -0,0 +1,88 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ok", + "claims": [ + { + "claim": "Water boils at 100 C at sea level.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "hello there", + "language": "en", + "status": "failed", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": { + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + } + }, + { + "claim": "vendor is down", + "language": "en", + "status": "failed", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + }, + { + "claim": "cannot frame", + "language": "en", + "status": "failed", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": { + "code": "framing_failed", + "detail": "The input could not be read as a claim.", + "hint": "This item could not be processed; retrying it as-is will not help. Send it rephrased as one factual statement; nothing was charged.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + } + } + ], + "failure": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__memo_hit.json b/tests/fixtures/parity/canonical/assess__memo_hit.json new file mode 100644 index 0000000..873c763 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__memo_hit.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ok", + "claims": [ + { + "claim": "The Danube flows through Vienna.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": "The river runs through the city.", + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + } + ], + "failure": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__replay_later_200.json b/tests/fixtures/parity/canonical/assess__replay_later_200.json new file mode 100644 index 0000000..bac5c15 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__replay_later_200.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "The Earth orbits the Sun.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__single_no_claim.json b/tests/fixtures/parity/canonical/assess__single_no_claim.json new file mode 100644 index 0000000..3a193c0 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__single_no_claim.json @@ -0,0 +1,21 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "no_checkable_claim", + "claims": [], + "failure": { + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "The input is a greeting, not a statement that can be checked. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__single_one_claim.json b/tests/fixtures/parity/canonical/assess__single_one_claim.json new file mode 100644 index 0000000..d27ac90 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__single_one_claim.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ok", + "claims": [ + { + "claim": "The registry reported 4,200 filings in 2024.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": "The registry lists 4,200 filings for 2024 and has not revised the figure.", + "dissent": "The registry figure is provisional, so the 2024 total cannot yet be confirmed.", + "suggested_rewrite": null, + "more_claims": [], + "failure": null + } + ], + "failure": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__single_text_over_wave_more_claims.json b/tests/fixtures/parity/canonical/assess__single_text_over_wave_more_claims.json new file mode 100644 index 0000000..1d4fc2e --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__single_text_over_wave_more_claims.json @@ -0,0 +1,278 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ok", + "claims": [ + { + "claim": "Claim number 0 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 1 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 2 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 3 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 4 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 5 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 6 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 7 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 8 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 9 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 10 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 11 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 12 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 13 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 14 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 15 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 16 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 17 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 18 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "Claim number 19 is documented.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + } + ], + "failure": null, + "more_claims": [ + "Claim number 20 is documented.", + "Claim number 21 is documented." + ] + } +} diff --git a/tests/fixtures/parity/canonical/assess__single_text_several_claims.json b/tests/fixtures/parity/canonical/assess__single_text_several_claims.json new file mode 100644 index 0000000..4313609 --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__single_text_several_claims.json @@ -0,0 +1,54 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ok", + "claims": [ + { + "claim": "Water boils at 100 C at sea level.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "The Moon is made of cheese.", + "language": "en", + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + { + "claim": "The Pacific is the deepest ocean.", + "language": "en", + "status": "completed", + "verdict": "Mostly True", + "confidence": "medium", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + } + ], + "failure": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/assess__suggest_rewrite.json b/tests/fixtures/parity/canonical/assess__suggest_rewrite.json new file mode 100644 index 0000000..d2aee3e --- /dev/null +++ b/tests/fixtures/parity/canonical/assess__suggest_rewrite.json @@ -0,0 +1,41 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ok", + "claims": [ + { + "claim": "Venus is the closest planet to the Sun.", + "language": "en", + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": "Mercury, not Venus, is the closest planet to the Sun.", + "dissent": null, + "suggested_rewrite": "Mercury is the closest planet to the Sun.", + "more_claims": [], + "failure": null + }, + { + "claim": "Mercury is the closest planet to the Sun.", + "language": "en", + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": "Mercury is the innermost planet.", + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + } + ], + "failure": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__402_no_credits.json b/tests/fixtures/parity/canonical/citecheck__402_no_credits.json new file mode 100644 index 0000000..dfb7db4 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__402_no_credits.json @@ -0,0 +1,18 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining credits for citation checks.", + "code": "no_credits", + "docs_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 100, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_empty_body.json b/tests/fixtures/parity/canonical/citecheck__422_empty_body.json new file mode 100644 index 0000000..82cdb99 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_empty_body.json @@ -0,0 +1,25 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload: Value error, send exactly one of text and pairs", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload" + ], + "msg": "Value error, send exactly one of text and pairs", + "type": "value_error", + "ctx": { + "error": "send exactly one of text and pairs" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_invalid_doi.json b/tests/fixtures/parity/canonical/citecheck__422_invalid_doi.json new file mode 100644 index 0000000..c3c1d4c --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_invalid_doi.json @@ -0,0 +1,25 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "pairs[0].doi: Send the DOI alone, like 10.1038/nature12373.", + "code": "invalid_doi", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0, + "doi" + ], + "msg": "Send the DOI alone, like 10.1038/nature12373.", + "type": "invalid_doi" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_max_citations_over_20.json b/tests/fixtures/parity/canonical/citecheck__422_max_citations_over_20.json new file mode 100644 index 0000000..610a9cd --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_max_citations_over_20.json @@ -0,0 +1,26 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "max_citations: Input should be less than or equal to 20", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "max_citations" + ], + "msg": "Input should be less than or equal to 20", + "type": "less_than_equal", + "ctx": { + "le": 20 + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_max_citations_with_pairs.json b/tests/fixtures/parity/canonical/citecheck__422_max_citations_with_pairs.json new file mode 100644 index 0000000..746f21f --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_max_citations_with_pairs.json @@ -0,0 +1,25 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload: Value error, max_citations goes with text: every pair is checked", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload" + ], + "msg": "Value error, max_citations goes with text: every pair is checked", + "type": "value_error", + "ctx": { + "error": "max_citations goes with text: every pair is checked" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_pair_bad_url_scheme.json b/tests/fixtures/parity/canonical/citecheck__422_pair_bad_url_scheme.json new file mode 100644 index 0000000..a791f53 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_pair_bad_url_scheme.json @@ -0,0 +1,28 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "pairs[0].url: Value error, url: an http or https link", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0, + "url" + ], + "msg": "Value error, url: an http or https link", + "type": "value_error", + "ctx": { + "error": "url: an http or https link" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_pair_no_source.json b/tests/fixtures/parity/canonical/citecheck__422_pair_no_source.json new file mode 100644 index 0000000..f7ac540 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_pair_no_source.json @@ -0,0 +1,27 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "pairs[0]: Value error, send exactly one of url and doi", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0 + ], + "msg": "Value error, send exactly one of url and doi", + "type": "value_error", + "ctx": { + "error": "send exactly one of url and doi" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_pair_url_and_doi.json b/tests/fixtures/parity/canonical/citecheck__422_pair_url_and_doi.json new file mode 100644 index 0000000..f7ac540 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_pair_url_and_doi.json @@ -0,0 +1,27 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "pairs[0]: Value error, send exactly one of url and doi", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0 + ], + "msg": "Value error, send exactly one of url and doi", + "type": "value_error", + "ctx": { + "error": "send exactly one of url and doi" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_pairs_empty.json b/tests/fixtures/parity/canonical/citecheck__422_pairs_empty.json new file mode 100644 index 0000000..9b2008e --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_pairs_empty.json @@ -0,0 +1,26 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "pairs: Value error, pairs: 1 to 20 items", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs" + ], + "msg": "Value error, pairs: 1 to 20 items", + "type": "value_error", + "ctx": { + "error": "pairs: 1 to 20 items" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_pairs_over_20.json b/tests/fixtures/parity/canonical/citecheck__422_pairs_over_20.json new file mode 100644 index 0000000..9b2008e --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_pairs_over_20.json @@ -0,0 +1,26 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "pairs: Value error, pairs: 1 to 20 items", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs" + ], + "msg": "Value error, pairs: 1 to 20 items", + "type": "value_error", + "ctx": { + "error": "pairs: 1 to 20 items" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_quote_not_in_statement.json b/tests/fixtures/parity/canonical/citecheck__422_quote_not_in_statement.json new file mode 100644 index 0000000..e4d2408 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_quote_not_in_statement.json @@ -0,0 +1,24 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "pairs[0]: Each quote must be words of its statement.", + "code": "quote_not_in_statement", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0 + ], + "msg": "Each quote must be words of its statement.", + "type": "quote_not_in_statement" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_text_and_pairs.json b/tests/fixtures/parity/canonical/citecheck__422_text_and_pairs.json new file mode 100644 index 0000000..82cdb99 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_text_and_pairs.json @@ -0,0 +1,25 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload: Value error, send exactly one of text and pairs", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload" + ], + "msg": "Value error, send exactly one of text and pairs", + "type": "value_error", + "ctx": { + "error": "send exactly one of text and pairs" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_unknown_field.json b/tests/fixtures/parity/canonical/citecheck__422_unknown_field.json new file mode 100644 index 0000000..0aed242 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_unknown_field.json @@ -0,0 +1,25 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "pairs[0].extra: Extra inputs are not permitted", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0, + "extra" + ], + "msg": "Extra inputs are not permitted", + "type": "extra_forbidden" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__422_url_input.json b/tests/fixtures/parity/canonical/citecheck__422_url_input.json new file mode 100644 index 0000000..816edbe --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_url_input.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Send the page's text, with its links, to check the sources it cites.", + "code": "url_input", + "errors": [ + { + "loc": [ + "body", + "text" + ], + "msg": "Send the page's text, with its links, to check the sources it cites.", + "type": "url_input" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__429_citecheck_in_flight.json b/tests/fixtures/parity/canonical/citecheck__429_citecheck_in_flight.json new file mode 100644 index 0000000..fa73820 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__429_citecheck_in_flight.json @@ -0,0 +1,14 @@ +{ + "status": 429, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This account already has 3 citation checks running. Wait for one to finish.", + "code": "citecheck_in_flight", + "retry_after": 60 + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__503_capacity.json b/tests/fixtures/parity/canonical/citecheck__503_capacity.json new file mode 100644 index 0000000..bcff7db --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__503_capacity.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": 90, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__503_citations_unavailable.json b/tests/fixtures/parity/canonical/citecheck__503_citations_unavailable.json new file mode 100644 index 0000000..cdeb748 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__503_citations_unavailable.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "300", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Citation checking is switched off right now. Retry later; nothing was charged.", + "code": "citations_unavailable", + "retry_after": 300, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_404_not_found.json b/tests/fixtures/parity/canonical/citecheck__get_404_not_found.json new file mode 100644 index 0000000..e0adfb3 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_404_not_found.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Citation check not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_404_review_id.json b/tests/fixtures/parity/canonical/citecheck__get_404_review_id.json new file mode 100644 index 0000000..e0adfb3 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_404_review_id.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Citation check not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_410_purged.json b/tests/fixtures/parity/canonical/citecheck__get_410_purged.json new file mode 100644 index 0000000..9fff981 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_410_purged.json @@ -0,0 +1,13 @@ +{ + "status": 410, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This check is no longer available: its account removes content after a set period.", + "code": "purged", + "purged_at": "2026-10-01T09:07:00.123456Z" + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_checking.json b/tests/fixtures/parity/canonical/citecheck__get_checking.json new file mode 100644 index 0000000..9ca9e92 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_checking.json @@ -0,0 +1,103 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "checking", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "poll_after_seconds": 10, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 0, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "pending", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "pending", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_clean.json b/tests/fixtures/parity/canonical/citecheck__get_completed_clean.json new file mode 100644 index 0000000..11e7ed2 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_clean.json @@ -0,0 +1,111 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 2 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_doi_pair.json b/tests/fixtures/parity/canonical/citecheck__get_completed_doi_pair.json new file mode 100644 index 0000000..49e62df --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_doi_pair.json @@ -0,0 +1,76 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 1 + }, + "summary": { + "citations_found": 1, + "citations_selected": 1, + "citation_limit": 1, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 1, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 1 + }, + "citations": [ + { + "index": 0, + "reference": "10.1038/nature12373", + "cited_url": "https://doi.org/10.1038/nature12373", + "doi": "10.1038/nature12373", + "statement": "Diamond sensors measure heat in cells.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at None", + "page_published_date": null, + "page_language": "en", + "source_url": null, + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_incomplete.json b/tests/fixtures/parity/canonical/citecheck__get_completed_incomplete.json new file mode 100644 index 0000000..a50708c --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_incomplete.json @@ -0,0 +1,129 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 1, + "unchecked": 0, + "failed": 1 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 1 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "failed", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": "The check failed on our side. Try again later.", + "failure": { + "code": "internal", + "detail": "The check failed on our side.", + "hint": "The check failed on our side. Try again later.", + "failure_class": "internal", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#internal" + }, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [ + { + "citation_index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "failure": { + "code": "internal", + "detail": "The check failed on our side.", + "hint": "The check failed on our side. Try again later.", + "failure_class": "internal", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#internal" + } + } + ], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_issues_found.json b/tests/fixtures/parity/canonical/citecheck__get_completed_issues_found.json new file mode 100644 index 0000000..1555b9a --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_issues_found.json @@ -0,0 +1,141 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 20 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 1 + }, + "credits": { + "charged": 2 + }, + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "contradicted", + "source": "support", + "is_issue": true + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "contradicted", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [ + { + "citation_index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "finding": "contradicted", + "source": "support", + "snippet": "The source says so.", + "rationale": "The page states it.", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "failure": null + } + ], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_partly_supported.json b/tests/fixtures/parity/canonical/citecheck__get_completed_partly_supported.json new file mode 100644 index 0000000..f1d95be --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_partly_supported.json @@ -0,0 +1,111 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 2 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": { + "finding": "partly_supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "partly_supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_unchecked.json b/tests/fixtures/parity/canonical/citecheck__get_completed_unchecked.json new file mode 100644 index 0000000..a37c4cb --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_unchecked.json @@ -0,0 +1,111 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 0, + "unchecked": 2, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": { + "finding": "unchecked", + "source": null, + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "unchecked", + "snippet": null, + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": "no_text", + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": { + "finding": "unchecked", + "source": null, + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "unchecked", + "snippet": null, + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": "no_text", + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_failed_no_citations.json b/tests/fixtures/parity/canonical/citecheck__get_failed_no_citations.json new file mode 100644 index 0000000..25625db --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_failed_no_citations.json @@ -0,0 +1,43 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 20 + }, + "summary": { + "citations_found": null, + "citations_selected": null, + "citation_limit": 20, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [], + "citation_issues": [], + "citation_failures": [], + "failure": { + "code": "no_citations", + "detail": "The text holds no citation to check.", + "hint": "The text has no citation to check: no link, DOI or numbered reference with one.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_failed_upstream_unavailable.json b/tests/fixtures/parity/canonical/citecheck__get_failed_upstream_unavailable.json new file mode 100644 index 0000000..a323d29 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_failed_upstream_unavailable.json @@ -0,0 +1,153 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 20 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 0, + "unchecked": 0, + "failed": 2 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": null, + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "failed", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": "Lenz could not reach this source just now. Try again later.", + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "Lenz could not reach this source just now. Try again later.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": null, + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "failed", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": "Lenz could not reach this source just now. Try again later.", + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "Lenz could not reach this source just now. Try again later.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [ + { + "citation_index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "Lenz could not reach this source just now. Try again later.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + }, + { + "citation_index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "Lenz could not reach this source just now. Try again later.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + } + ], + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": null, + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_queued.json b/tests/fixtures/parity/canonical/citecheck__get_queued.json new file mode 100644 index 0000000..df7dfee --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_queued.json @@ -0,0 +1,72 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "queued", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "poll_after_seconds": 10, + "policy": { + "max_citations": 1 + }, + "summary": { + "citations_found": 1, + "citations_selected": 1, + "citation_limit": 1, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 0, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "pending", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_text_limit_exactly_at_limit.json b/tests/fixtures/parity/canonical/citecheck__get_text_limit_exactly_at_limit.json new file mode 100644 index 0000000..600d1b9 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_text_limit_exactly_at_limit.json @@ -0,0 +1,119 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 2 + }, + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__get_text_limit_reached.json b/tests/fixtures/parity/canonical/citecheck__get_text_limit_reached.json new file mode 100644 index 0000000..a4dbb6b --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__get_text_limit_reached.json @@ -0,0 +1,93 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 1 + }, + "summary": { + "citations_found": 2, + "citations_selected": 1, + "citation_limit": 1, + "citation_limit_exceeded": true, + "citation_checks": { + "checked": 1, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 1 + }, + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [ + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "sentence": "The agency said so in a statement.", + "position": { + "start": 111, + "end": 178, + "text": null + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__idempotency_body_mismatch_422.json b/tests/fixtures/parity/canonical/citecheck__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..e20089e --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__idempotency_body_mismatch_422.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__idempotency_conflict_409.json b/tests/fixtures/parity/canonical/citecheck__idempotency_conflict_409.json new file mode 100644 index 0000000..3978a83 --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__idempotency_conflict_409.json @@ -0,0 +1,13 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "A check with this Idempotency-Key is still being created. Retry shortly.", + "code": "idempotency_conflict", + "citecheck_id": null + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__idempotent_replay_202.json b/tests/fixtures/parity/canonical/citecheck__idempotent_replay_202.json new file mode 100644 index 0000000..864551e --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__idempotent_replay_202.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/citechecks/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__receipt_202.json b/tests/fixtures/parity/canonical/citecheck__receipt_202.json new file mode 100644 index 0000000..864551e --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__receipt_202.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/citechecks/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/canonical/citecheck__receipt_202_empty_webhook_url.json new file mode 100644 index 0000000..864551e --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__receipt_202_empty_webhook_url.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/citechecks/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/errors__ask_bad_language.json b/tests/fixtures/parity/canonical/errors__ask_bad_language.json new file mode 100644 index 0000000..e543e6d --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__ask_bad_language.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unsupported language 'xx-nope'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "code": "unsupported_language", + "errors": [ + { + "loc": [ + "body", + "language" + ], + "msg": "Unsupported language 'xx-nope'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "type": "unsupported_language" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/errors__ask_empty_message.json b/tests/fixtures/parity/canonical/errors__ask_empty_message.json new file mode 100644 index 0000000..86f7435 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__ask_empty_message.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Message cannot be empty.", + "code": "blank_input", + "errors": [ + { + "loc": [ + "body", + "message" + ], + "msg": "Message cannot be empty.", + "type": "blank_input" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/errors__ask_failed.json b/tests/fixtures/parity/canonical/errors__ask_failed.json new file mode 100644 index 0000000..df45b1c --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__ask_failed.json @@ -0,0 +1,12 @@ +{ + "status": 502, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The chat model could not answer this question.", + "code": "ask_failed" + } +} diff --git a/tests/fixtures/parity/canonical/errors__ask_idempotency_key_reused.json b/tests/fixtures/parity/canonical/errors__ask_idempotency_key_reused.json new file mode 100644 index 0000000..e20089e --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__ask_idempotency_key_reused.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + } +} diff --git a/tests/fixtures/parity/canonical/errors__ask_message_too_long.json b/tests/fixtures/parity/canonical/errors__ask_message_too_long.json new file mode 100644 index 0000000..80b5bab --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__ask_message_too_long.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Message too long (max 500 characters).", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "message" + ], + "msg": "Message too long (max 500 characters).", + "type": "validation_error" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/errors__ask_not_completed.json b/tests/fixtures/parity/canonical/errors__ask_not_completed.json new file mode 100644 index 0000000..9800c71 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__ask_not_completed.json @@ -0,0 +1,12 @@ +{ + "status": 400, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Ask is only available for completed verifications.", + "code": "verification_not_ready" + } +} diff --git a/tests/fixtures/parity/canonical/errors__ask_reset_not_found.json b/tests/fixtures/parity/canonical/errors__ask_reset_not_found.json new file mode 100644 index 0000000..3eec577 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__ask_reset_not_found.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Verification not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/errors__ask_send_not_found.json b/tests/fixtures/parity/canonical/errors__ask_send_not_found.json new file mode 100644 index 0000000..3eec577 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__ask_send_not_found.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Verification not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_bad_key.json b/tests/fixtures/parity/canonical/errors__auth_bad_key.json new file mode 100644 index 0000000..1c3df51 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_bad_key.json @@ -0,0 +1,12 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_basic_scheme.json b/tests/fixtures/parity/canonical/errors__auth_basic_scheme.json new file mode 100644 index 0000000..1c3df51 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_basic_scheme.json @@ -0,0 +1,12 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_insufficient_scope.json b/tests/fixtures/parity/canonical/errors__auth_insufficient_scope.json new file mode 100644 index 0000000..15b8696 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_insufficient_scope.json @@ -0,0 +1,14 @@ +{ + "status": 403, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "WWW-Authenticate": "Bearer error=\"insufficient_scope\", scope=\"verify\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The access token does not allow this call.", + "code": "insufficient_scope", + "scope": "verify" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_missing_bearer.json b/tests/fixtures/parity/canonical/errors__auth_missing_bearer.json new file mode 100644 index 0000000..1c3df51 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_missing_bearer.json @@ -0,0 +1,12 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_missing_bearer_post.json b/tests/fixtures/parity/canonical/errors__auth_missing_bearer_post.json new file mode 100644 index 0000000..1c3df51 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_missing_bearer_post.json @@ -0,0 +1,12 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_history.json b/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_history.json new file mode 100644 index 0000000..3445e87 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_history.json @@ -0,0 +1,12 @@ +{ + "status": 403, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This report is private.", + "code": "private_claim" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_send.json b/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_send.json new file mode 100644 index 0000000..3445e87 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_send.json @@ -0,0 +1,12 @@ +{ + "status": 403, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This report is private.", + "code": "private_claim" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_unrecognised_prefix.json b/tests/fixtures/parity/canonical/errors__auth_unrecognised_prefix.json new file mode 100644 index 0000000..1c3df51 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_unrecognised_prefix.json @@ -0,0 +1,12 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + } +} diff --git a/tests/fixtures/parity/canonical/errors__http_error_library_bad_curated.json b/tests/fixtures/parity/canonical/errors__http_error_library_bad_curated.json new file mode 100644 index 0000000..76cbe7a --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__http_error_library_bad_curated.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Invalid curated list(s). Allowed: trivia", + "code": "validation_error", + "errors": [ + { + "loc": [ + "query", + "curated" + ], + "msg": "Invalid curated list(s). Allowed: trivia", + "type": "validation_error" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/errors__http_error_library_bad_verdict.json b/tests/fixtures/parity/canonical/errors__http_error_library_bad_verdict.json new file mode 100644 index 0000000..09dbe2e --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__http_error_library_bad_verdict.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Invalid verdict label(s). Allowed: False, Mostly False, Mixed, Mostly True, True", + "code": "validation_error", + "errors": [ + { + "loc": [ + "query", + "verdict" + ], + "msg": "Invalid verdict label(s). Allowed: False, Mostly False, Mixed, Mostly True, True", + "type": "validation_error" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/errors__not_found_ask.json b/tests/fixtures/parity/canonical/errors__not_found_ask.json new file mode 100644 index 0000000..3eec577 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__not_found_ask.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Verification not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/errors__not_found_route.json b/tests/fixtures/parity/canonical/errors__not_found_route.json new file mode 100644 index 0000000..f1a8c33 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__not_found_route.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/errors__not_found_verification.json b/tests/fixtures/parity/canonical/errors__not_found_verification.json new file mode 100644 index 0000000..f1a8c33 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__not_found_verification.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/errors__not_found_verify_status.json b/tests/fixtures/parity/canonical/errors__not_found_verify_status.json new file mode 100644 index 0000000..ed0bc13 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__not_found_verify_status.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Task not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/errors__payment_required_ask.json b/tests/fixtures/parity/canonical/errors__payment_required_ask.json new file mode 100644 index 0000000..e4bc4cf --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__payment_required_ask.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining ask credits.", + "code": "no_credits", + "docs_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/canonical/errors__payment_required_assess.json b/tests/fixtures/parity/canonical/errors__payment_required_assess.json new file mode 100644 index 0000000..5e931cc --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__payment_required_assess.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining /assess units.", + "code": "no_credits", + "docs_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/canonical/errors__payment_required_verify.json b/tests/fixtures/parity/canonical/errors__payment_required_verify.json new file mode 100644 index 0000000..1f73a67 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__payment_required_verify.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining claim checks.", + "code": "no_credits", + "docs_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 10 + } +} diff --git a/tests/fixtures/parity/canonical/errors__payment_required_verify_batch_short.json b/tests/fixtures/parity/canonical/errors__payment_required_verify_batch_short.json new file mode 100644 index 0000000..e80d840 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__payment_required_verify_batch_short.json @@ -0,0 +1,20 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Insufficient credits for batch.", + "code": "no_credits", + "docs_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "requested": 5, + "remaining": 3, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 30, + "cost": 50 + } +} diff --git a/tests/fixtures/parity/canonical/errors__rate_limited_extract.json b/tests/fixtures/parity/canonical/errors__rate_limited_extract.json new file mode 100644 index 0000000..e45b708 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__rate_limited_extract.json @@ -0,0 +1,17 @@ +{ + "status": 429, + "headers": { + "Content-Type": "application/json", + "Retry-After": "900", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", + "code": "extract_daily_limit", + "limit": 1000, + "retry_after": 900, + "docs_url": "https://lenz.io/docs/errors#rate-limits", + "upgrade_url": "https://lenz.io/plans" + } +} diff --git a/tests/fixtures/parity/canonical/errors__service_unavailable_ask.json b/tests/fixtures/parity/canonical/errors__service_unavailable_ask.json new file mode 100644 index 0000000..94a09cd --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__service_unavailable_ask.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The chat model is unavailable right now. Retry shortly.", + "code": "upstream_unavailable", + "retry_after": 90, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/errors__service_unavailable_capacity.json b/tests/fixtures/parity/canonical/errors__service_unavailable_capacity.json new file mode 100644 index 0000000..cc8fad8 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__service_unavailable_capacity.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": 60, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/errors__validation_malformed_json.json b/tests/fixtures/parity/canonical/errors__validation_malformed_json.json new file mode 100644 index 0000000..9e1f37c --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__validation_malformed_json.json @@ -0,0 +1,12 @@ +{ + "status": 400, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The request body is not valid JSON.", + "code": "malformed_body" + } +} diff --git a/tests/fixtures/parity/canonical/errors__validation_missing_field_hint.json b/tests/fixtures/parity/canonical/errors__validation_missing_field_hint.json new file mode 100644 index 0000000..2cf69f1 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__validation_missing_field_hint.json @@ -0,0 +1,29 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "text: Field required", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ], + "hint": "Required field 'text' is missing. Unrecognised fields: content, bogus.", + "docs_url": "https://lenz.io/docs/errors#validation", + "unrecognized_fields": [ + "content", + "bogus" + ] + } +} diff --git a/tests/fixtures/parity/canonical/errors__validation_unknown_field_only.json b/tests/fixtures/parity/canonical/errors__validation_unknown_field_only.json new file mode 100644 index 0000000..877dab6 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__validation_unknown_field_only.json @@ -0,0 +1,28 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claim: Field required", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ], + "hint": "Required field 'claim' is missing. Unrecognised fields: statement.", + "docs_url": "https://lenz.io/docs/errors#validation", + "unrecognized_fields": [ + "statement" + ] + } +} diff --git a/tests/fixtures/parity/canonical/errors__validation_unknown_field_wrong_type.json b/tests/fixtures/parity/canonical/errors__validation_unknown_field_wrong_type.json new file mode 100644 index 0000000..1aae12f --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__validation_unknown_field_wrong_type.json @@ -0,0 +1,27 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claims: Input should be a valid list", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "claims" + ], + "msg": "Input should be a valid list", + "type": "list_type" + } + ], + "unrecognized_fields": [ + "bogus_field", + "another" + ] + } +} diff --git a/tests/fixtures/parity/canonical/errors__validation_wrong_type.json b/tests/fixtures/parity/canonical/errors__validation_wrong_type.json new file mode 100644 index 0000000..843bab6 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__validation_wrong_type.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "text: Input should be a valid string", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Input should be a valid string", + "type": "string_type" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/extract__401_no_key.json b/tests/fixtures/parity/canonical/extract__401_no_key.json new file mode 100644 index 0000000..1c3df51 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__401_no_key.json @@ -0,0 +1,12 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + } +} diff --git a/tests/fixtures/parity/canonical/extract__422_blank_text.json b/tests/fixtures/parity/canonical/extract__422_blank_text.json new file mode 100644 index 0000000..4242aac --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__422_blank_text.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Text is required.", + "code": "blank_input", + "errors": [ + { + "loc": [ + "body", + "text" + ], + "msg": "Text is required.", + "type": "blank_input" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/extract__422_focus_too_long.json b/tests/fixtures/parity/canonical/extract__422_focus_too_long.json new file mode 100644 index 0000000..6645b81 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__422_focus_too_long.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "focus must be at most 300 characters of plain text.", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "focus" + ], + "msg": "focus must be at most 300 characters of plain text.", + "type": "validation_error" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/extract__422_missing_text.json b/tests/fixtures/parity/canonical/extract__422_missing_text.json new file mode 100644 index 0000000..eb7b0fc --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__422_missing_text.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "text: Field required", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/extract__429_daily_limit.json b/tests/fixtures/parity/canonical/extract__429_daily_limit.json new file mode 100644 index 0000000..23ae05b --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__429_daily_limit.json @@ -0,0 +1,17 @@ +{ + "status": 429, + "headers": { + "Content-Type": "application/json", + "Retry-After": "3600", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", + "code": "extract_daily_limit", + "limit": 1000, + "retry_after": 3600, + "docs_url": "https://lenz.io/docs/errors#rate-limits", + "upgrade_url": "https://lenz.io/plans" + } +} diff --git a/tests/fixtures/parity/canonical/extract__502_extraction_failed.json b/tests/fixtures/parity/canonical/extract__502_extraction_failed.json new file mode 100644 index 0000000..62f2e63 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__502_extraction_failed.json @@ -0,0 +1,12 @@ +{ + "status": 502, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Extraction failed", + "code": "extraction_failed" + } +} diff --git a/tests/fixtures/parity/canonical/extract__503_upstream_unavailable.json b/tests/fixtures/parity/canonical/extract__503_upstream_unavailable.json new file mode 100644 index 0000000..3315806 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__503_upstream_unavailable.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Our model providers are temporarily unavailable. Please retry shortly.", + "code": "upstream_unavailable", + "retry_after": 90, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/extract__focus_ready.json b/tests/fixtures/parity/canonical/extract__focus_ready.json new file mode 100644 index 0000000..29eccf2 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__focus_ready.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claims": [ + { + "claim": "Beta fell 3% last year.", + "positions": null + } + ], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + } +} diff --git a/tests/fixtures/parity/canonical/extract__idempotency_body_mismatch_422.json b/tests/fixtures/parity/canonical/extract__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..e20089e --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__idempotency_body_mismatch_422.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + } +} diff --git a/tests/fixtures/parity/canonical/extract__idempotency_replay.json b/tests/fixtures/parity/canonical/extract__idempotency_replay.json new file mode 100644 index 0000000..b508889 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__idempotency_replay.json @@ -0,0 +1,34 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claims": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": null + }, + { + "claim": "Beta fell 3% last year.", + "positions": null + } + ], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + } +} diff --git a/tests/fixtures/parity/canonical/extract__locate_all_dropped.json b/tests/fixtures/parity/canonical/extract__locate_all_dropped.json new file mode 100644 index 0000000..7906518 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__locate_all_dropped.json @@ -0,0 +1,25 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "no_checkable_claim", + "claims": [], + "domain": "", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + } +} diff --git a/tests/fixtures/parity/canonical/extract__locate_failed.json b/tests/fixtures/parity/canonical/extract__locate_failed.json new file mode 100644 index 0000000..2fbe6a7 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__locate_failed.json @@ -0,0 +1,34 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claims": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": null + }, + { + "claim": "Beta fell 3% last year.", + "positions": null + } + ], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + } +} diff --git a/tests/fixtures/parity/canonical/extract__locate_leading_whitespace.json b/tests/fixtures/parity/canonical/extract__locate_leading_whitespace.json new file mode 100644 index 0000000..8033e2d --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__locate_leading_whitespace.json @@ -0,0 +1,36 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claims": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "start": 3, + "end": 25, + "text": "Alpha rose 5% in 2024." + } + ] + } + ], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + } +} diff --git a/tests/fixtures/parity/canonical/extract__locate_some_dropped.json b/tests/fixtures/parity/canonical/extract__locate_some_dropped.json new file mode 100644 index 0000000..11529fa --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__locate_some_dropped.json @@ -0,0 +1,46 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claims": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "start": 0, + "end": 22, + "text": "Alpha rose 5% in 2024." + } + ] + }, + { + "claim": "Beta fell 3% last year.", + "positions": [ + { + "start": 23, + "end": 46, + "text": "Beta fell 3% last year." + } + ] + } + ], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + } +} diff --git a/tests/fixtures/parity/canonical/extract__locate_true.json b/tests/fixtures/parity/canonical/extract__locate_true.json new file mode 100644 index 0000000..11529fa --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__locate_true.json @@ -0,0 +1,46 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claims": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "start": 0, + "end": 22, + "text": "Alpha rose 5% in 2024." + } + ] + }, + { + "claim": "Beta fell 3% last year.", + "positions": [ + { + "start": 23, + "end": 46, + "text": "Beta fell 3% last year." + } + ] + } + ], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + } +} diff --git a/tests/fixtures/parity/canonical/extract__no_match_with_focus.json b/tests/fixtures/parity/canonical/extract__no_match_with_focus.json new file mode 100644 index 0000000..eceaf0b --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__no_match_with_focus.json @@ -0,0 +1,16 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "no_match", + "claims": [], + "domain": "", + "key_entities": [], + "presumed_intent": "", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + } +} diff --git a/tests/fixtures/parity/canonical/extract__not_a_claim.json b/tests/fixtures/parity/canonical/extract__not_a_claim.json new file mode 100644 index 0000000..df06a66 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__not_a_claim.json @@ -0,0 +1,16 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "no_checkable_claim", + "claims": [], + "domain": "", + "key_entities": [], + "presumed_intent": "", + "original_input": "What a lovely day." + } +} diff --git a/tests/fixtures/parity/canonical/extract__not_a_claim_beside_claims.json b/tests/fixtures/parity/canonical/extract__not_a_claim_beside_claims.json new file mode 100644 index 0000000..646bbad --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__not_a_claim_beside_claims.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claims": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": null + } + ], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024." + } +} diff --git a/tests/fixtures/parity/canonical/extract__ready_one_claim.json b/tests/fixtures/parity/canonical/extract__ready_one_claim.json new file mode 100644 index 0000000..646bbad --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__ready_one_claim.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claims": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": null + } + ], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024." + } +} diff --git a/tests/fixtures/parity/canonical/extract__ready_several_claims.json b/tests/fixtures/parity/canonical/extract__ready_several_claims.json new file mode 100644 index 0000000..2fbe6a7 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__ready_several_claims.json @@ -0,0 +1,34 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claims": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": null + }, + { + "claim": "Beta fell 3% last year.", + "positions": null + } + ], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + } +} diff --git a/tests/fixtures/parity/canonical/extract__replay_later_200.json b/tests/fixtures/parity/canonical/extract__replay_later_200.json new file mode 100644 index 0000000..8fff1c2 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__replay_later_200.json @@ -0,0 +1,31 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": null + } +} diff --git a/tests/fixtures/parity/canonical/extract__url_fetch_502_unreadable.json b/tests/fixtures/parity/canonical/extract__url_fetch_502_unreadable.json new file mode 100644 index 0000000..62f2e63 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__url_fetch_502_unreadable.json @@ -0,0 +1,12 @@ +{ + "status": 502, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Extraction failed", + "code": "extraction_failed" + } +} diff --git a/tests/fixtures/parity/canonical/extract__url_fetch_503_upstream.json b/tests/fixtures/parity/canonical/extract__url_fetch_503_upstream.json new file mode 100644 index 0000000..14eded6 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__url_fetch_503_upstream.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The page could not be read right now. Please retry shortly.", + "code": "upstream_unavailable", + "retry_after": 90, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/extract__url_input_located.json b/tests/fixtures/parity/canonical/extract__url_input_located.json new file mode 100644 index 0000000..5c97376 --- /dev/null +++ b/tests/fixtures/parity/canonical/extract__url_input_located.json @@ -0,0 +1,36 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claims": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "start": null, + "end": null, + "text": "Alpha rose 5% in 2024." + } + ] + } + ], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "https://example.com/an-article" + } +} diff --git a/tests/fixtures/parity/canonical/review__401_no_credentials.json b/tests/fixtures/parity/canonical/review__401_no_credentials.json new file mode 100644 index 0000000..1c3df51 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__401_no_credentials.json @@ -0,0 +1,12 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + } +} diff --git a/tests/fixtures/parity/canonical/review__402_no_credits.json b/tests/fixtures/parity/canonical/review__402_no_credits.json new file mode 100644 index 0000000..5a9f5be --- /dev/null +++ b/tests/fixtures/parity/canonical/review__402_no_credits.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining credits to assess the draft.", + "code": "no_credits", + "docs_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 100, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 100, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/canonical/review__402_no_credits_exhausted.json b/tests/fixtures/parity/canonical/review__402_no_credits_exhausted.json new file mode 100644 index 0000000..2ec177c --- /dev/null +++ b/tests/fixtures/parity/canonical/review__402_no_credits_exhausted.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining credits to assess the draft.", + "code": "no_credits", + "docs_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/canonical/review__422_blank_text.json b/tests/fixtures/parity/canonical/review__422_blank_text.json new file mode 100644 index 0000000..ee12b17 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_blank_text.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "text: send the draft, or one public http(s) URL.", + "code": "blank_input", + "errors": [ + { + "loc": [ + "body", + "text" + ], + "msg": "text: send the draft, or one public http(s) URL.", + "type": "blank_input" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_citations_options_object.json b/tests/fixtures/parity/canonical/review__422_citations_options_object.json new file mode 100644 index 0000000..8932e84 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_citations_options_object.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "citations: Extra inputs are not permitted", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "citations" + ], + "msg": "Extra inputs are not permitted", + "type": "extra_forbidden" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_depth_unknown.json b/tests/fixtures/parity/canonical/review__422_depth_unknown.json new file mode 100644 index 0000000..3ef5a12 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_depth_unknown.json @@ -0,0 +1,27 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "escalate.depth: Input should be 'standard' or 'low'", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "depth" + ], + "msg": "Input should be 'standard' or 'low'", + "type": "literal_error", + "ctx": { + "expected": "'standard' or 'low'" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_invalid_confidence_band.json b/tests/fixtures/parity/canonical/review__422_invalid_confidence_band.json new file mode 100644 index 0000000..9ece217 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_invalid_confidence_band.json @@ -0,0 +1,27 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "escalate.confidence: Unknown confidence band 'certain'; use low, medium or high.", + "code": "invalid_confidence_band", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "confidence" + ], + "msg": "Unknown confidence band 'certain'; use low, medium or high.", + "type": "invalid_confidence_band", + "ctx": { + "band": "certain" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_invalid_verdict_label.json b/tests/fixtures/parity/canonical/review__422_invalid_verdict_label.json new file mode 100644 index 0000000..ea83a57 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_invalid_verdict_label.json @@ -0,0 +1,28 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "escalate.verdicts: Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True.", + "code": "invalid_verdict_label", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "verdicts" + ], + "msg": "Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True.", + "type": "invalid_verdict_label", + "ctx": { + "label": "Misleading", + "labels": "False, Mostly False, Mixed, Mostly True, True" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_max_assessments_negative.json b/tests/fixtures/parity/canonical/review__422_max_assessments_negative.json new file mode 100644 index 0000000..0bb1242 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_max_assessments_negative.json @@ -0,0 +1,27 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "escalate.max_assessments: Input should be greater than or equal to 0", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_assessments" + ], + "msg": "Input should be greater than or equal to 0", + "type": "greater_than_equal", + "ctx": { + "ge": 0 + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_max_citations_negative.json b/tests/fixtures/parity/canonical/review__422_max_citations_negative.json new file mode 100644 index 0000000..dd2cde4 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_max_citations_negative.json @@ -0,0 +1,27 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "escalate.max_citations: Input should be greater than or equal to 0", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_citations" + ], + "msg": "Input should be greater than or equal to 0", + "type": "greater_than_equal", + "ctx": { + "ge": 0 + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_max_citations_too_big.json b/tests/fixtures/parity/canonical/review__422_max_citations_too_big.json new file mode 100644 index 0000000..3d8860c --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_max_citations_too_big.json @@ -0,0 +1,27 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "escalate.max_citations: Input should be less than or equal to 20", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_citations" + ], + "msg": "Input should be less than or equal to 20", + "type": "less_than_equal", + "ctx": { + "le": 20 + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_max_verifications_too_big.json b/tests/fixtures/parity/canonical/review__422_max_verifications_too_big.json new file mode 100644 index 0000000..cc5e5b1 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_max_verifications_too_big.json @@ -0,0 +1,27 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "escalate.max_verifications: Input should be less than or equal to 20", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_verifications" + ], + "msg": "Input should be less than or equal to 20", + "type": "less_than_equal", + "ctx": { + "le": 20 + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_text_missing.json b/tests/fixtures/parity/canonical/review__422_text_missing.json new file mode 100644 index 0000000..eb7b0fc --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_text_missing.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "text: Field required", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_text_wrong_type.json b/tests/fixtures/parity/canonical/review__422_text_wrong_type.json new file mode 100644 index 0000000..843bab6 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_text_wrong_type.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "text: Input should be a valid string", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Input should be a valid string", + "type": "string_type" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_unknown_escalate_field.json b/tests/fixtures/parity/canonical/review__422_unknown_escalate_field.json new file mode 100644 index 0000000..74bc52a --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_unknown_escalate_field.json @@ -0,0 +1,24 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "escalate.nope: Extra inputs are not permitted", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "nope" + ], + "msg": "Extra inputs are not permitted", + "type": "extra_forbidden" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_unknown_top_level_field.json b/tests/fixtures/parity/canonical/review__422_unknown_top_level_field.json new file mode 100644 index 0000000..eecb052 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_unknown_top_level_field.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "max_verifications: Extra inputs are not permitted", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "max_verifications" + ], + "msg": "Extra inputs are not permitted", + "type": "extra_forbidden" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_unsupported_language.json b/tests/fixtures/parity/canonical/review__422_unsupported_language.json new file mode 100644 index 0000000..9382428 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_unsupported_language.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "code": "unsupported_language", + "errors": [ + { + "loc": [ + "body", + "language" + ], + "msg": "Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "type": "unsupported_language" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__422_visibility_public.json b/tests/fixtures/parity/canonical/review__422_visibility_public.json new file mode 100644 index 0000000..31600c2 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_visibility_public.json @@ -0,0 +1,26 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "visibility: Input should be 'private' or 'unlisted'", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "visibility" + ], + "msg": "Input should be 'private' or 'unlisted'", + "type": "literal_error", + "ctx": { + "expected": "'private' or 'unlisted'" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__429_extract_daily_limit.json b/tests/fixtures/parity/canonical/review__429_extract_daily_limit.json new file mode 100644 index 0000000..320069f --- /dev/null +++ b/tests/fixtures/parity/canonical/review__429_extract_daily_limit.json @@ -0,0 +1,17 @@ +{ + "status": 429, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Daily /extract limit of 1000 reached for this account. A review of a URL reads the page like /extract and counts as one /extract call.", + "code": "extract_daily_limit", + "limit": 1000, + "retry_after": 60, + "docs_url": "https://lenz.io/docs/errors#rate-limits", + "upgrade_url": "https://lenz.io/plans" + } +} diff --git a/tests/fixtures/parity/canonical/review__429_review_in_flight.json b/tests/fixtures/parity/canonical/review__429_review_in_flight.json new file mode 100644 index 0000000..61295d1 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__429_review_in_flight.json @@ -0,0 +1,14 @@ +{ + "status": 429, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This account already has 3 reviews running. Retry when one completes.", + "code": "review_in_flight", + "retry_after": 60 + } +} diff --git a/tests/fixtures/parity/canonical/review__503_capacity.json b/tests/fixtures/parity/canonical/review__503_capacity.json new file mode 100644 index 0000000..bcff7db --- /dev/null +++ b/tests/fixtures/parity/canonical/review__503_capacity.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": 90, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/review__503_citations_capacity.json b/tests/fixtures/parity/canonical/review__503_citations_capacity.json new file mode 100644 index 0000000..bcff7db --- /dev/null +++ b/tests/fixtures/parity/canonical/review__503_citations_capacity.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": 90, + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/review__get_403_insufficient_scope.json b/tests/fixtures/parity/canonical/review__get_403_insufficient_scope.json new file mode 100644 index 0000000..80c529c --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_403_insufficient_scope.json @@ -0,0 +1,14 @@ +{ + "status": 403, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "WWW-Authenticate": "Bearer error=\"insufficient_scope\", scope=\"history:read\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The access token does not allow this call.", + "code": "insufficient_scope", + "scope": "history:read" + } +} diff --git a/tests/fixtures/parity/canonical/review__get_404_not_found.json b/tests/fixtures/parity/canonical/review__get_404_not_found.json new file mode 100644 index 0000000..8045cd8 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_404_not_found.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Review not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/review__get_404_other_account.json b/tests/fixtures/parity/canonical/review__get_404_other_account.json new file mode 100644 index 0000000..8045cd8 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_404_other_account.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Review not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/review__get_410_purged.json b/tests/fixtures/parity/canonical/review__get_410_purged.json new file mode 100644 index 0000000..bedf6a5 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_410_purged.json @@ -0,0 +1,13 @@ +{ + "status": 410, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This review is no longer available: its account removes content after a set period.", + "code": "purged", + "purged_at": "2026-10-01T09:07:00.123456Z" + } +} diff --git a/tests/fixtures/parity/canonical/review__get_422_unknown_view.json b/tests/fixtures/parity/canonical/review__get_422_unknown_view.json new file mode 100644 index 0000000..a9df405 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_422_unknown_view.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "view: use full or issues.", + "code": "validation_error", + "errors": [ + { + "loc": [ + "query", + "view" + ], + "msg": "view: use full or issues.", + "type": "validation_error" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_assessing.json b/tests/fixtures/parity/canonical/review__get_assessing.json new file mode 100644 index 0000000..1b8bc1d --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_assessing.json @@ -0,0 +1,107 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "assessing", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 0, + "failed": 0 + }, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": 10, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": null, + "assessment": { + "status": "running", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": null, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": null, + "assessment": { + "status": "running", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": null, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_assessment_rows_full_fields.json b/tests/fixtures/parity/canonical/review__get_assessment_rows_full_fields.json new file mode 100644 index 0000000..8680925 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_assessment_rows_full_fields.json @@ -0,0 +1,169 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 0, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 1 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": null, + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "cap" + }, + "key_finding": null, + "rationale": "Two reviewers found the date wrong.", + "suggested_rewrite": "The EU AI Act entered into force in August 2024.", + "failure": null, + "suggested_edits": null + } + ], + "failures": [ + { + "claim_index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "stage": "assessment", + "failure": { + "code": "timeout", + "detail": "The check did not finish inside its time budget.", + "hint": "The check ran out of time. Retry it; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "assessment", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": "Two reviewers found the date wrong.", + "dissent": "One reviewer read the claim as about the entry into force.", + "suggested_rewrite": "The EU AI Act entered into force in August 2024.", + "more_claims": [ + "The EU AI Act took effect in 2024.", + "It took effect in March." + ], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "cap" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": null, + "assessment": { + "status": "failed", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": { + "code": "timeout", + "detail": "The check did not finish inside its time budget.", + "hint": "The check ran out of time. Retry it; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": null + } + }, + "escalation": null, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_clean.json b/tests/fixtures/parity/canonical/review__get_citations_clean.json new file mode 100644 index 0000000..332658b --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_clean.json @@ -0,0 +1,182 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 3 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_failed_and_unchecked.json b/tests/fixtures/parity/canonical/review__get_citations_failed_and_unchecked.json new file mode 100644 index 0000000..b180507 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_failed_and_unchecked.json @@ -0,0 +1,200 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 0, + "unchecked": 1, + "failed": 1 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [ + { + "citation_index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": { + "code": "internal", + "detail": "The check failed on our side.", + "hint": "The check failed on our side. Try again later.", + "failure_class": "internal", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#internal" + } + } + ], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": null, + "check": { + "status": "failed", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": "The check failed on our side. Try again later.", + "failure": { + "code": "internal", + "detail": "The check failed on our side.", + "hint": "The check failed on our side. Try again later.", + "failure_class": "internal", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#internal" + }, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "unchecked", + "source": null, + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "unchecked", + "snippet": null, + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": "no_text", + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_issue_full.json b/tests/fixtures/parity/canonical/review__get_citations_issue_full.json new file mode 100644 index 0000000..b3243d6 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_issue_full.json @@ -0,0 +1,204 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 1, + "citations_skipped": null + }, + "credits": { + "charged": 3 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [ + { + "citation_index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "finding": "contradicted", + "source": "support", + "snippet": "The source says so.", + "rationale": "The page states it.", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "failure": null + } + ], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "contradicted", + "source": "support", + "is_issue": true + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "contradicted", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_issue_issues_view.json b/tests/fixtures/parity/canonical/review__get_citations_issue_issues_view.json new file mode 100644 index 0000000..9f60f10 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_issue_issues_view.json @@ -0,0 +1,94 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "issues", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 1, + "citations_skipped": null + }, + "credits": { + "charged": 3 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [ + { + "citation_index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "finding": "contradicted", + "source": "support", + "snippet": "The source says so.", + "rationale": "The page states it.", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "failure": null + } + ], + "citation_failures": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_limit_exactly_at_limit.json b/tests/fixtures/parity/canonical/review__get_citations_limit_exactly_at_limit.json new file mode 100644 index 0000000..a81b16f --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_limit_exactly_at_limit.json @@ -0,0 +1,182 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 2, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 3 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_limit_reached.json b/tests/fixtures/parity/canonical/review__get_citations_limit_reached.json new file mode 100644 index 0000000..33eeb1b --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_limit_reached.json @@ -0,0 +1,156 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 1, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 1, + "citation_limit": 1, + "citation_limit_exceeded": true, + "citation_checks": { + "checked": 1, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [ + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "sentence": "The agency said so in a statement.", + "position": { + "start": 111, + "end": 178, + "text": null + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_no_claim_but_citations.json b/tests/fixtures/parity/canonical/review__get_citations_no_claim_but_citations.json new file mode 100644 index 0000000..fbb5a29 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_no_claim_but_citations.json @@ -0,0 +1,153 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": 0, + "claims_selected": 0, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 0, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_no_claim_no_citation.json b/tests/fixtures/parity/canonical/review__get_citations_no_claim_no_citation.json new file mode 100644 index 0000000..e9cdd01 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_no_claim_no_citation.json @@ -0,0 +1,70 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": null, + "claims_selected": null, + "claim_limit": 20, + "claim_limit_exceeded": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": 20, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": { + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_not_asked.json b/tests/fixtures/parity/canonical/review__get_citations_not_asked.json new file mode 100644 index 0000000..27d5c36 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_not_asked.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_only.json b/tests/fixtures/parity/canonical/review__get_citations_only.json new file mode 100644 index 0000000..4a86304 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_only.json @@ -0,0 +1,160 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 0, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 0, + "claim_limit": 0, + "claim_limit_exceeded": true, + "input_truncated": false, + "assessments": { + "completed": 0, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [ + "The EU AI Act took effect in March 2024." + ], + "more_claim_locations": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "positions": null + } + ], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_partly_supported.json b/tests/fixtures/parity/canonical/review__get_citations_partly_supported.json new file mode 100644 index 0000000..44488cd --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_partly_supported.json @@ -0,0 +1,182 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 3 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "partly_supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "partly_supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_running.json b/tests/fixtures/parity/canonical/review__get_citations_running.json new file mode 100644 index 0000000..ff45b91 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_running.json @@ -0,0 +1,166 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "verifying", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_exceeded": false, + "citation_checks": { + "checked": 0, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": 15, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": null, + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "pending", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": null, + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "pending", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_skipped_switched_off.json b/tests/fixtures/parity/canonical/review__get_citations_skipped_switched_off.json new file mode 100644 index 0000000..acfa95b --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_skipped_switched_off.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": 20, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": "switched_off" + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_citations_skipped_url_input.json b/tests/fixtures/parity/canonical/review__get_citations_skipped_url_input.json new file mode 100644 index 0000000..5919306 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_citations_skipped_url_input.json @@ -0,0 +1,70 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_found": null, + "claims_selected": null, + "claim_limit": 20, + "claim_limit_exceeded": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": 20, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": "url_input" + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": null, + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/canonical/review__get_claim_limit_not_reached.json b/tests/fixtures/parity/canonical/review__get_claim_limit_not_reached.json new file mode 100644 index 0000000..548c3c8 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_claim_limit_not_reached.json @@ -0,0 +1,127 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 3, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 3, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_claim_limit_reached_exact.json b/tests/fixtures/parity/canonical/review__get_claim_limit_reached_exact.json new file mode 100644 index 0000000..6432f12 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_claim_limit_reached_exact.json @@ -0,0 +1,127 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 2, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 2, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_completed_assess_only.json b/tests/fixtures/parity/canonical/review__get_completed_assess_only.json new file mode 100644 index 0000000..107ee44 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_completed_assess_only.json @@ -0,0 +1,153 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 0, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": null, + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "cap" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "assessment", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "cap" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_completed_clean.json b/tests/fixtures/parity/canonical/review__get_completed_clean.json new file mode 100644 index 0000000..0849314 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_completed_clean.json @@ -0,0 +1,127 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Paris is the capital of France.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_completed_issues_all_verified.json b/tests/fixtures/parity/canonical/review__get_completed_issues_all_verified.json new file mode 100644 index 0000000..1b82d0e --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_completed_issues_all_verified.json @@ -0,0 +1,256 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 3, + "claims_selected": 3, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 3, + "failed": 0 + }, + "verifications": { + "planned": 2, + "completed": 2, + "failed": 0 + }, + "issues": 2, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 23 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "failure": null, + "suggested_edits": null + }, + { + "claim_index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b79019e4", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", + "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "Mostly False", + "confidence": "medium", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "c010dca9a43543f518e49f4ec7842ceb", + "verification_id": "b4e2e99d", + "claim": "The EU AI Act took effect in March 2024.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "executive_summary": "Summary for The EU AI Act took effect in March 2024.", + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T09:49:00.123456+00:00", + "completed_at": "2026-10-01T09:56:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "failure": null + }, + "suggested_edits": null + }, + { + "index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "4e02e88b137711f18ba7758af5c40837", + "verification_id": "b79019e4", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T09:49:00.123456+00:00", + "completed_at": "2026-10-01T09:56:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", + "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "failure": null + }, + "suggested_edits": null + }, + { + "index": 2, + "claim": "Paris is the capital of France.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_completed_issues_full.json b/tests/fixtures/parity/canonical/review__get_completed_issues_full.json new file mode 100644 index 0000000..ff3d65d --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_completed_issues_full.json @@ -0,0 +1,309 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 4, + "claims_selected": 4, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 3, + "failed": 1 + }, + "verifications": { + "planned": 2, + "completed": 1, + "failed": 1 + }, + "issues": 2, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 13 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "failure": null, + "suggested_edits": null + }, + { + "claim_index": 2, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": "failed", + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": { + "code": "research_empty", + "detail": "No sources about the claim were found.", + "hint": null, + "failure_class": "insufficient_evidence", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + }, + "suggested_edits": null + } + ], + "failures": [ + { + "claim_index": 1, + "claim": "Water boils at 100 C at sea level.", + "stage": "assessment", + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + } + ], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "Mostly False", + "confidence": "medium", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "7df4009bc27aab64ce5d5a01fbafe599", + "verification_id": "b4e2e99d", + "claim": "The EU AI Act took effect in March 2024.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "executive_summary": "Summary for The EU AI Act took effect in March 2024.", + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T09:42:00.123456+00:00", + "completed_at": "2026-10-01T09:49:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "failure": null + }, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": null, + "assessment": { + "status": "failed", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + }, + "escalation": null, + "verification": null, + "suggested_edits": null + }, + { + "index": 2, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "assessment", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "verification_id": null, + "task_id": "4634b89821fd877f1edf8aaeb82b7ee5", + "claim": null, + "language": null, + "visibility": null, + "depth": null, + "domain": null, + "entities": [], + "verdict": null, + "confidence": null, + "lenz_score": null, + "key_finding": null, + "executive_summary": null, + "suggested_rewrite": null, + "warnings": [], + "created_at": null, + "completed_at": null, + "verification_url": null, + "url": null, + "failure": { + "code": "research_empty", + "detail": "No sources about the claim were found.", + "hint": null, + "failure_class": "insufficient_evidence", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + }, + "status": "failed", + "content_status": "available" + }, + "suggested_edits": null + }, + { + "index": 3, + "claim": "Paris is the capital of France.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_completed_issues_view_issues.json b/tests/fixtures/parity/canonical/review__get_completed_issues_view_issues.json new file mode 100644 index 0000000..a136287 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_completed_issues_view_issues.json @@ -0,0 +1,136 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "issues", + "status": "completed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 4, + "claims_selected": 4, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 3, + "failed": 1 + }, + "verifications": { + "planned": 2, + "completed": 1, + "failed": 1 + }, + "issues": 2, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 13 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "failure": null, + "suggested_edits": null + }, + { + "claim_index": 2, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": "failed", + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": { + "code": "research_empty", + "detail": "No sources about the claim were found.", + "hint": null, + "failure_class": "insufficient_evidence", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + }, + "suggested_edits": null + } + ], + "failures": [ + { + "claim_index": 1, + "claim": "Water boils at 100 C at sea level.", + "stage": "assessment", + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_completed_positions.json b/tests/fixtures/parity/canonical/review__get_completed_positions.json new file mode 100644 index 0000000..7a3c9e1 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_completed_positions.json @@ -0,0 +1,139 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": [ + { + "start": 0, + "end": 40, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": [ + { + "start": 55, + "end": 89, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_completed_recovered_claim.json b/tests/fixtures/parity/canonical/review__get_completed_recovered_claim.json new file mode 100644 index 0000000..aafdbe0 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_completed_recovered_claim.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "Orbit Motors stock increased by 40% in 2022.", + "positions": [], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_completed_with_untraced_claim.json b/tests/fixtures/parity/canonical/review__get_completed_with_untraced_claim.json new file mode 100644 index 0000000..64ad9f0 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_completed_with_untraced_claim.json @@ -0,0 +1,139 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": [ + { + "start": 0, + "end": 40, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": [ + { + "start": 50, + "end": 84, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_during_quick_check.json b/tests/fixtures/parity/canonical/review__get_during_quick_check.json new file mode 100644 index 0000000..06f27e1 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_during_quick_check.json @@ -0,0 +1,87 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "assessing", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 0, + "failed": 0 + }, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": 10, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": null, + "assessment": { + "status": "running", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": null, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_failed_every_assessment_failed.json b/tests/fixtures/parity/canonical/review__get_failed_every_assessment_failed.json new file mode 100644 index 0000000..93ea710 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_failed_every_assessment_failed.json @@ -0,0 +1,159 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "failed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 0, + "failed": 2 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "stage": "assessment", + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + }, + { + "claim_index": 1, + "claim": "Water boils at 100 C at sea level.", + "stage": "assessment", + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + } + ], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": null, + "assessment": { + "status": "failed", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + }, + "escalation": null, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": null, + "assessment": { + "status": "failed", + "verdict": null, + "confidence": null, + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": { + "code": "upstream_unavailable", + "detail": "A service the check depends on was unavailable.", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + }, + "escalation": null, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": { + "code": "assessment_failed", + "detail": "No claim could be assessed.", + "hint": "Retry the review with a new Idempotency-Key; nothing was charged.", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_failed_no_claim.json b/tests/fixtures/parity/canonical/review__get_failed_no_claim.json new file mode 100644 index 0000000..d8506ac --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_failed_no_claim.json @@ -0,0 +1,70 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": null, + "claims_selected": null, + "claim_limit": 20, + "claim_limit_exceeded": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": { + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "The text is a greeting, not a statement about the world. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/canonical/review__get_failed_no_claim_untraced.json b/tests/fixtures/parity/canonical/review__get_failed_no_claim_untraced.json new file mode 100644 index 0000000..9d2e2ea --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_failed_no_claim_untraced.json @@ -0,0 +1,70 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": null, + "claims_selected": null, + "claim_limit": 20, + "claim_limit_exceeded": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": { + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "None of the claims found in the text could be traced back to it. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/canonical/review__get_more_claims.json b/tests/fixtures/parity/canonical/review__get_more_claims.json new file mode 100644 index 0000000..ffaacb2 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_more_claims.json @@ -0,0 +1,152 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 2, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 3, + "claims_selected": 2, + "claim_limit": 2, + "claim_limit_exceeded": true, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": [ + { + "start": 0, + "end": 40, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": [ + { + "start": 50, + "end": 84, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [ + "The Eiffel Tower is in Berlin." + ], + "more_claim_locations": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "positions": [ + { + "start": 91, + "end": 121, + "text": "The Eiffel Tower is in Berlin." + } + ] + } + ], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..62d9316 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,150 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 1, + "completed": 1, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 11 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "7df4009bc27aab64ce5d5a01fbafe599", + "verification_id": "b4e2e99d", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T23:55:00.123456+00:00", + "completed_at": "2026-10-02T00:03:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "failure": null + }, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..1aeb435 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_same_day_hours_apart.json @@ -0,0 +1,150 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 1, + "completed": 1, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 11 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "7df4009bc27aab64ce5d5a01fbafe599", + "verification_id": "b4e2e99d", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T08:00:00.123456+00:00", + "completed_at": "2026-10-01T20:00:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "failure": null + }, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_policy_resolved.json b/tests/fixtures/parity/canonical/review__get_policy_resolved.json new file mode 100644 index 0000000..cc1e568 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_policy_resolved.json @@ -0,0 +1,97 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 2, + "depth": "low", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_queued.json b/tests/fixtures/parity/canonical/review__get_queued.json new file mode 100644 index 0000000..1b08c33 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_queued.json @@ -0,0 +1,63 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "queued", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": null, + "claims_selected": null, + "claim_limit": 20, + "claim_limit_exceeded": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": 10, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": null, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/canonical/review__get_suggested_edits.json b/tests/fixtures/parity/canonical/review__get_suggested_edits.json new file mode 100644 index 0000000..8f4e0a0 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_suggested_edits.json @@ -0,0 +1,266 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "verifying", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "suggest_edits": true, + "max_citations": 0 + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 2, + "completed": 1, + "failed": 0 + }, + "issues": 2, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 12 + }, + "poll_after_seconds": 15, + "issues": [ + { + "claim_index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "7c83247c", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": { + "status": "completed", + "edits": [ + { + "position": 0, + "start": 23, + "end": 29, + "text": "Berlin", + "replacement": "Paris" + } + ] + } + }, + { + "claim_index": 1, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": null, + "suggested_edits": { + "status": "pending", + "edits": null + } + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "positions": [ + { + "start": 0, + "end": 30, + "text": "The Eiffel Tower is in Berlin." + } + ], + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "9bca1e0819de60a750186e812dc58e2b", + "verification_id": "7c83247c", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T09:35:00.123456+00:00", + "completed_at": "2026-10-01T09:42:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "failure": null + }, + "suggested_edits": { + "status": "completed", + "edits": [ + { + "position": 0, + "start": 23, + "end": 29, + "text": "Berlin", + "replacement": "Paris" + } + ] + } + }, + { + "index": 1, + "claim": "The EU AI Act took effect in March 2024.", + "positions": [ + { + "start": 45, + "end": 85, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "verdict": "False", + "confidence": "high", + "source": "assessment", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "processing", + "content_status": "available", + "verification_id": null, + "task_id": null, + "claim": null, + "language": null, + "visibility": null, + "depth": null, + "domain": null, + "entities": [], + "verdict": null, + "confidence": null, + "lenz_score": null, + "key_finding": null, + "executive_summary": null, + "suggested_rewrite": null, + "warnings": [], + "created_at": null, + "completed_at": null, + "verification_url": null, + "url": null, + "failure": null + }, + "suggested_edits": { + "status": "pending", + "edits": null + } + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_suggested_edits_issues_view.json b/tests/fixtures/parity/canonical/review__get_suggested_edits_issues_view.json new file mode 100644 index 0000000..8914521 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_suggested_edits_issues_view.json @@ -0,0 +1,129 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "issues", + "status": "verifying", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "suggest_edits": true, + "max_citations": 0 + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 2, + "completed": 1, + "failed": 0 + }, + "issues": 2, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 12 + }, + "poll_after_seconds": 15, + "issues": [ + { + "claim_index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "7c83247c", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": { + "status": "completed", + "edits": [ + { + "position": 0, + "start": 23, + "end": 29, + "text": "Berlin", + "replacement": "Paris" + } + ] + } + }, + { + "claim_index": 1, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": null, + "suggested_edits": { + "status": "pending", + "edits": null + } + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_url_review.json b/tests/fixtures/parity/canonical/review__get_url_review.json new file mode 100644 index 0000000..90ea98e --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_url_review.json @@ -0,0 +1,105 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 1, + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": [ + { + "start": null, + "end": null, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__get_verifying.json b/tests/fixtures/parity/canonical/review__get_verifying.json new file mode 100644 index 0000000..1663113 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__get_verifying.json @@ -0,0 +1,176 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "verifying", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_found": 2, + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_exceeded": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 1, + "completed": 0, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_exceeded": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": 15, + "issues": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "assessment", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "processing", + "content_status": "available", + "verification_id": null, + "task_id": null, + "claim": null, + "language": null, + "visibility": null, + "depth": null, + "domain": null, + "entities": [], + "verdict": null, + "confidence": null, + "lenz_score": null, + "key_finding": null, + "executive_summary": null, + "suggested_rewrite": null, + "warnings": [], + "created_at": null, + "completed_at": null, + "verification_url": null, + "url": null, + "failure": null + }, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "more_claims": [], + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/canonical/review__idempotency_body_mismatch_422.json b/tests/fixtures/parity/canonical/review__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..e20089e --- /dev/null +++ b/tests/fixtures/parity/canonical/review__idempotency_body_mismatch_422.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + } +} diff --git a/tests/fixtures/parity/canonical/review__idempotency_conflict_409.json b/tests/fixtures/parity/canonical/review__idempotency_conflict_409.json new file mode 100644 index 0000000..8bbdff7 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__idempotency_conflict_409.json @@ -0,0 +1,13 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "A review with this Idempotency-Key is still being created. Retry shortly.", + "code": "idempotency_conflict", + "review_id": null + } +} diff --git a/tests/fixtures/parity/canonical/review__idempotency_conflict_409_existing_review.json b/tests/fixtures/parity/canonical/review__idempotency_conflict_409_existing_review.json new file mode 100644 index 0000000..edef440 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__idempotency_conflict_409_existing_review.json @@ -0,0 +1,13 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "A review with this Idempotency-Key is still being created. Retry shortly.", + "code": "idempotency_conflict", + "review_id": "d6b2bd72" + } +} diff --git a/tests/fixtures/parity/canonical/review__idempotent_replay_202.json b/tests/fixtures/parity/canonical/review__idempotent_replay_202.json new file mode 100644 index 0000000..6a0872b --- /dev/null +++ b/tests/fixtures/parity/canonical/review__idempotent_replay_202.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/reviews/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/review__receipt_202.json b/tests/fixtures/parity/canonical/review__receipt_202.json new file mode 100644 index 0000000..6a0872b --- /dev/null +++ b/tests/fixtures/parity/canonical/review__receipt_202.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/reviews/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/review__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/canonical/review__receipt_202_empty_webhook_url.json new file mode 100644 index 0000000..6a0872b --- /dev/null +++ b/tests/fixtures/parity/canonical/review__receipt_202_empty_webhook_url.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/reviews/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/review__receipt_202_webhook_url.json b/tests/fixtures/parity/canonical/review__receipt_202_webhook_url.json new file mode 100644 index 0000000..6a0872b --- /dev/null +++ b/tests/fixtures/parity/canonical/review__receipt_202_webhook_url.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/reviews/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/review__replay_later_202.json b/tests/fixtures/parity/canonical/review__replay_later_202.json new file mode 100644 index 0000000..6a0872b --- /dev/null +++ b/tests/fixtures/parity/canonical/review__replay_later_202.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/reviews/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/verify__batch_202.json b/tests/fixtures/parity/canonical/verify__batch_202.json new file mode 100644 index 0000000..be544f2 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__batch_202.json @@ -0,0 +1,21 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "claim": "The Earth is round." + }, + { + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "claim": "Water boils at 100C at sea level." + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__batch_capacity_503.json b/tests/fixtures/parity/canonical/verify__batch_capacity_503.json new file mode 100644 index 0000000..2e25ef0 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__batch_capacity_503.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": "", + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/verify__batch_empty_422.json b/tests/fixtures/parity/canonical/verify__batch_empty_422.json new file mode 100644 index 0000000..0082c60 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__batch_empty_422.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claims is required and must be non-empty.", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "claims" + ], + "msg": "claims is required and must be non-empty.", + "type": "validation_error" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__batch_idempotency_conflict_409.json b/tests/fixtures/parity/canonical/verify__batch_idempotency_conflict_409.json new file mode 100644 index 0000000..788b394 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__batch_idempotency_conflict_409.json @@ -0,0 +1,13 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "A request with this Idempotency-Key is already in progress.", + "code": "idempotency_conflict", + "task_id": "7cff18d" + } +} diff --git a/tests/fixtures/parity/canonical/verify__batch_item_missing_claim_422.json b/tests/fixtures/parity/canonical/verify__batch_item_missing_claim_422.json new file mode 100644 index 0000000..7017bcc --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__batch_item_missing_claim_422.json @@ -0,0 +1,25 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claims[1].claim: Field required", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "claims", + 1, + "text" + ], + "msg": "Field required", + "type": "missing" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__batch_no_credits_402.json b/tests/fixtures/parity/canonical/verify__batch_no_credits_402.json new file mode 100644 index 0000000..8991dc1 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__batch_no_credits_402.json @@ -0,0 +1,20 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Insufficient credits for batch.", + "code": "no_credits", + "docs_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "requested": 1, + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 10 + } +} diff --git a/tests/fixtures/parity/canonical/verify__batch_partial_202.json b/tests/fixtures/parity/canonical/verify__batch_partial_202.json new file mode 100644 index 0000000..1e3656f --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__batch_partial_202.json @@ -0,0 +1,18 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "claim": "First claim." + } + ], + "partial": true + } +} diff --git a/tests/fixtures/parity/canonical/verify__batch_too_many_422.json b/tests/fixtures/parity/canonical/verify__batch_too_many_422.json new file mode 100644 index 0000000..5105df7 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__batch_too_many_422.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Batch size exceeds maximum of 20.", + "code": "too_many_items", + "errors": [ + { + "loc": [ + "body", + "claims" + ], + "msg": "Batch size exceeds maximum of 20.", + "type": "too_many_items" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__blank_claim_422.json b/tests/fixtures/parity/canonical/verify__blank_claim_422.json new file mode 100644 index 0000000..a5a1062 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__blank_claim_422.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claim is required.", + "code": "blank_input", + "errors": [ + { + "loc": [ + "body", + "claim" + ], + "msg": "claim is required.", + "type": "blank_input" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__capacity_503.json b/tests/fixtures/parity/canonical/verify__capacity_503.json new file mode 100644 index 0000000..2e25ef0 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__capacity_503.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": "", + "docs_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/canonical/verify__idempotency_body_mismatch_422.json b/tests/fixtures/parity/canonical/verify__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..e20089e --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__idempotency_body_mismatch_422.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + } +} diff --git a/tests/fixtures/parity/canonical/verify__idempotency_conflict_409.json b/tests/fixtures/parity/canonical/verify__idempotency_conflict_409.json new file mode 100644 index 0000000..1f8ddf5 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__idempotency_conflict_409.json @@ -0,0 +1,13 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "A request with this Idempotency-Key is already in progress.", + "code": "idempotency_conflict", + "task_id": "7cff18da2d979d6370e54a160be121ad" + } +} diff --git a/tests/fixtures/parity/canonical/verify__idempotency_key_replay.json b/tests/fixtures/parity/canonical/verify__idempotency_key_replay.json new file mode 100644 index 0000000..b510371 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__idempotency_key_replay.json @@ -0,0 +1,12 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/verify__implicit_dedup_200.json b/tests/fixtures/parity/canonical/verify__implicit_dedup_200.json new file mode 100644 index 0000000..b510371 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__implicit_dedup_200.json @@ -0,0 +1,12 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/verify__implicit_repeat_replay.json b/tests/fixtures/parity/canonical/verify__implicit_repeat_replay.json new file mode 100644 index 0000000..b510371 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__implicit_repeat_replay.json @@ -0,0 +1,12 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/verify__invalid_depth_422.json b/tests/fixtures/parity/canonical/verify__invalid_depth_422.json new file mode 100644 index 0000000..ae4883c --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__invalid_depth_422.json @@ -0,0 +1,26 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "depth: Input should be 'standard' or 'low'", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "depth" + ], + "msg": "Input should be 'standard' or 'low'", + "type": "literal_error", + "ctx": { + "expected": "'standard' or 'low'" + } + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__invalid_language_422.json b/tests/fixtures/parity/canonical/verify__invalid_language_422.json new file mode 100644 index 0000000..5e82c5f --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__invalid_language_422.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unsupported language 'xx-not-a-language'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "code": "unsupported_language", + "errors": [ + { + "loc": [ + "body", + "language" + ], + "msg": "Unsupported language 'xx-not-a-language'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "type": "unsupported_language" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__list_200.json b/tests/fixtures/parity/canonical/verify__list_200.json new file mode 100644 index 0000000..0b7e73b --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__list_200.json @@ -0,0 +1,45 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "language": "en" + }, + { + "verification_id": "b4e2e99d", + "claim": "The Earth is round.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:35:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "language": "en" + } + ], + "total": 2, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/verify__list_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/verify__list_200_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..267a53e --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__list_200_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "completed_at": "2026-10-02T00:03:00.123456+00:00", + "language": "en" + } + ], + "total": 1, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/verify__list_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/verify__list_200_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..65e23bc --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__list_200_modified_at_same_day_hours_apart.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "completed_at": "2026-10-01T20:00:00.123456+00:00", + "language": "en" + } + ], + "total": 1, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/verify__list_clamped_200.json b/tests/fixtures/parity/canonical/verify__list_clamped_200.json new file mode 100644 index 0000000..3d639d4 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__list_clamped_200.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [], + "total": 0, + "page": 1, + "page_size": 100 + } +} diff --git a/tests/fixtures/parity/canonical/verify__list_empty_200.json b/tests/fixtures/parity/canonical/verify__list_empty_200.json new file mode 100644 index 0000000..b419316 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__list_empty_200.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [], + "total": 0, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/canonical/verify__list_page2_200.json b/tests/fixtures/parity/canonical/verify__list_page2_200.json new file mode 100644 index 0000000..f83290d --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__list_page2_200.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "language": "en" + } + ], + "total": 3, + "page": 2, + "page_size": 2 + } +} diff --git a/tests/fixtures/parity/canonical/verify__misnamed_field_422.json b/tests/fixtures/parity/canonical/verify__misnamed_field_422.json new file mode 100644 index 0000000..877dab6 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__misnamed_field_422.json @@ -0,0 +1,28 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claim: Field required", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ], + "hint": "Required field 'claim' is missing. Unrecognised fields: statement.", + "docs_url": "https://lenz.io/docs/errors#validation", + "unrecognized_fields": [ + "statement" + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__missing_claim_422.json b/tests/fixtures/parity/canonical/verify__missing_claim_422.json new file mode 100644 index 0000000..9136471 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__missing_claim_422.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claim: Field required", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__no_credits_402.json b/tests/fixtures/parity/canonical/verify__no_credits_402.json new file mode 100644 index 0000000..1f73a67 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__no_credits_402.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining claim checks.", + "code": "no_credits", + "docs_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 10 + } +} diff --git a/tests/fixtures/parity/canonical/verify__replay_later_202.json b/tests/fixtures/parity/canonical/verify__replay_later_202.json new file mode 100644 index 0000000..b6dbf5e --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__replay_later_202.json @@ -0,0 +1,13 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "78ac4e9f234ea3bd" + } +} diff --git a/tests/fixtures/parity/canonical/verify__select_202.json b/tests/fixtures/parity/canonical/verify__select_202.json new file mode 100644 index 0000000..be544f2 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__select_202.json @@ -0,0 +1,21 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "claim": "The Earth is round." + }, + { + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "claim": "Water boils at 100C at sea level." + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__select_empty_422.json b/tests/fixtures/parity/canonical/verify__select_empty_422.json new file mode 100644 index 0000000..8651afb --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__select_empty_422.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claims is required.", + "code": "blank_input", + "errors": [ + { + "loc": [ + "body", + "claims" + ], + "msg": "claims is required.", + "type": "blank_input" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__select_invalid_selection_422.json b/tests/fixtures/parity/canonical/verify__select_invalid_selection_422.json new file mode 100644 index 0000000..d8f6dd6 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__select_invalid_selection_422.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Selected text was not one of the offered claims: 'The Moon is made of cheese.'", + "code": "invalid_selection", + "errors": [ + { + "loc": [ + "body", + "claims" + ], + "msg": "Selected text was not one of the offered claims: 'The Moon is made of cheese.'", + "type": "invalid_selection" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__select_no_selection_pending_409.json b/tests/fixtures/parity/canonical/verify__select_no_selection_pending_409.json new file mode 100644 index 0000000..149402e --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__select_no_selection_pending_409.json @@ -0,0 +1,12 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This task has no pending claim selection.", + "code": "no_selection_pending" + } +} diff --git a/tests/fixtures/parity/canonical/verify__select_too_many_422.json b/tests/fixtures/parity/canonical/verify__select_too_many_422.json new file mode 100644 index 0000000..db644a3 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__select_too_many_422.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Cannot select more than 20 claims.", + "code": "too_many_items", + "errors": [ + { + "loc": [ + "body", + "claims" + ], + "msg": "Cannot select more than 20 claims.", + "type": "too_many_items" + } + ] + } +} diff --git a/tests/fixtures/parity/canonical/verify__select_unknown_task_404.json b/tests/fixtures/parity/canonical/verify__select_unknown_task_404.json new file mode 100644 index 0000000..ed0bc13 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__select_unknown_task_404.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Task not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_cancelled_after_a_while.json b/tests/fixtures/parity/canonical/verify__status_cancelled_after_a_while.json new file mode 100644 index 0000000..799ffa9 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_cancelled_after_a_while.json @@ -0,0 +1,20 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "cancelled", + "detail": "The check was cancelled.", + "hint": null, + "failure_class": "cancelled", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#cancelled" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_completed.json b/tests/fixtures/parity/canonical/verify__status_completed.json new file mode 100644 index 0000000..c0ae291 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_completed.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "completed_at": "2026-10-01T09:28:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_completed_after_a_while.json b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while.json new file mode 100644 index 0000000..c0ae291 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "completed_at": "2026-10-01T09:28:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..64eb71f --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "completed_at": "2026-10-02T00:03:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..2cad36e --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "completed_at": "2026-10-01T20:00:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/verify__status_completed_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..64eb71f --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_completed_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "completed_at": "2026-10-02T00:03:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/verify__status_completed_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..2cad36e --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_completed_modified_at_same_day_hours_apart.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "completed_at": "2026-10-01T20:00:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_failed.json b/tests/fixtures/parity/canonical/verify__status_failed.json new file mode 100644 index 0000000..f0674e2 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_failed.json @@ -0,0 +1,20 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "research_empty", + "detail": "No sources about the claim were found.", + "hint": null, + "failure_class": "insufficient_evidence", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_failed_after_a_while.json b/tests/fixtures/parity/canonical/verify__status_failed_after_a_while.json new file mode 100644 index 0000000..7deb947 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_failed_after_a_while.json @@ -0,0 +1,20 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "conclusion_failed", + "detail": "The check stopped while writing the conclusion.", + "hint": null, + "failure_class": "internal", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#internal" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_failed_after_a_while_framing.json b/tests/fixtures/parity/canonical/verify__status_failed_after_a_while_framing.json new file mode 100644 index 0000000..1329048 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_failed_after_a_while_framing.json @@ -0,0 +1,20 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "framing_failed", + "detail": "The input could not be read as a claim.", + "hint": null, + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_failed_retryable.json b/tests/fixtures/parity/canonical/verify__status_failed_retryable.json new file mode 100644 index 0000000..b7594ed --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_failed_retryable.json @@ -0,0 +1,20 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "adjudication_failed", + "detail": "The check stopped while the reviewers scored the evidence.", + "hint": null, + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_needs_input.json b/tests/fixtures/parity/canonical/verify__status_needs_input.json new file mode 100644 index 0000000..194a4c6 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_needs_input.json @@ -0,0 +1,24 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "needs_input", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "reason": "multi_claim", + "claims": [ + { + "claim": "The Earth is round.", + "domain": "Science" + }, + { + "claim": "Water boils at 100C at sea level.", + "domain": "Science" + } + ], + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select." + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_not_a_claim.json b/tests/fixtures/parity/canonical/verify__status_not_a_claim.json new file mode 100644 index 0000000..dea790c --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_not_a_claim.json @@ -0,0 +1,20 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "The input is a greeting, not a statement that can be checked. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_not_a_claim_after_a_while.json b/tests/fixtures/parity/canonical/verify__status_not_a_claim_after_a_while.json new file mode 100644 index 0000000..d8a3007 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_not_a_claim_after_a_while.json @@ -0,0 +1,20 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_not_yours_404.json b/tests/fixtures/parity/canonical/verify__status_not_yours_404.json new file mode 100644 index 0000000..ed0bc13 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_not_yours_404.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Task not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_older_run_completed.json b/tests/fixtures/parity/canonical/verify__status_older_run_completed.json new file mode 100644 index 0000000..c0ae291 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_older_run_completed.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "completed_at": "2026-10-01T09:28:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_older_run_failed_crashed.json b/tests/fixtures/parity/canonical/verify__status_older_run_failed_crashed.json new file mode 100644 index 0000000..3966046 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_older_run_failed_crashed.json @@ -0,0 +1,20 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "task_error", + "detail": "The check stopped on an error on our side.", + "hint": null, + "failure_class": "internal", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#internal" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_older_run_failed_insufficient_evidence.json b/tests/fixtures/parity/canonical/verify__status_older_run_failed_insufficient_evidence.json new file mode 100644 index 0000000..f0674e2 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_older_run_failed_insufficient_evidence.json @@ -0,0 +1,20 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "research_empty", + "detail": "No sources about the claim were found.", + "hint": null, + "failure_class": "insufficient_evidence", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_older_run_in_progress.json b/tests/fixtures/parity/canonical/verify__status_older_run_in_progress.json new file mode 100644 index 0000000..8ff9472 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_older_run_in_progress.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "progress": { + "step": "research", + "index": 2, + "total": 5, + "elapsed_seconds": 2, + "poll_after_seconds": 5 + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_processing.json b/tests/fixtures/parity/canonical/verify__status_processing.json new file mode 100644 index 0000000..8ff9472 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_processing.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "progress": { + "step": "research", + "index": 2, + "total": 5, + "elapsed_seconds": 2, + "poll_after_seconds": 5 + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_processing_after_a_while.json b/tests/fixtures/parity/canonical/verify__status_processing_after_a_while.json new file mode 100644 index 0000000..077dee8 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_processing_after_a_while.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "progress": { + "step": "adjudication", + "index": 4, + "total": 5, + "elapsed_seconds": 2, + "poll_after_seconds": 5 + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_task_stuck.json b/tests/fixtures/parity/canonical/verify__status_task_stuck.json new file mode 100644 index 0000000..8230e8c --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_task_stuck.json @@ -0,0 +1,20 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "task_stuck", + "detail": "The check stopped responding before it finished.", + "hint": null, + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__status_unknown_404.json b/tests/fixtures/parity/canonical/verify__status_unknown_404.json new file mode 100644 index 0000000..ed0bc13 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__status_unknown_404.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Task not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/verify__submit_202.json b/tests/fixtures/parity/canonical/verify__submit_202.json new file mode 100644 index 0000000..b510371 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__submit_202.json @@ -0,0 +1,12 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/verify__submit_202_options.json b/tests/fixtures/parity/canonical/verify__submit_202_options.json new file mode 100644 index 0000000..b510371 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__submit_202_options.json @@ -0,0 +1,12 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/verify__submit_202_text_alias.json b/tests/fixtures/parity/canonical/verify__submit_202_text_alias.json new file mode 100644 index 0000000..b510371 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__submit_202_text_alias.json @@ -0,0 +1,12 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/canonical/verify__unauthenticated_401.json b/tests/fixtures/parity/canonical/verify__unauthenticated_401.json new file mode 100644 index 0000000..1c3df51 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__unauthenticated_401.json @@ -0,0 +1,12 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_200.json b/tests/fixtures/parity/canonical/verify__verification_200.json new file mode 100644 index 0000000..e6d5f88 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_200.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_200_covered.json b/tests/fixtures/parity/canonical/verify__verification_200_covered.json new file mode 100644 index 0000000..ab1972e --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_200_covered.json @@ -0,0 +1,93 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "covered", + "reasons": [], + "certificate_id": "df2c8d27663c61f5a32c2c628d182f81", + "certificate_url": "https://lenz.io/certificate/df2c8d27663c61f5a32c2c628d182f81", + "as_of": "2026-03-10T12:01:30+00:00", + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..9b01ef7 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "completed_at": "2026-10-02T00:03:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_null.json b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_null.json new file mode 100644 index 0000000..3cd999b --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_null.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..6a57a82 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_same_day_hours_apart.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "completed_at": "2026-10-01T20:00:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_set.json b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_set.json new file mode 100644 index 0000000..9b01ef7 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_set.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "completed_at": "2026-10-02T00:03:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_200_result_json_conclusion_only.json b/tests/fixtures/parity/canonical/verify__verification_200_result_json_conclusion_only.json new file mode 100644 index 0000000..68f5a3f --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_200_result_json_conclusion_only.json @@ -0,0 +1,56 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [], + "presumed_intent": "", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "sources": [], + "audit": { + "adjudication_summary": "", + "assessments": [], + "debate_pro": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "debate_con": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "panel_agreement": "split" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_200_result_json_empty.json b/tests/fixtures/parity/canonical/verify__verification_200_result_json_empty.json new file mode 100644 index 0000000..68f5a3f --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_200_result_json_empty.json @@ -0,0 +1,56 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [], + "presumed_intent": "", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "sources": [], + "audit": { + "adjudication_summary": "", + "assessments": [], + "debate_pro": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "debate_con": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "panel_agreement": "split" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_200_result_json_old_shape_strings.json b/tests/fixtures/parity/canonical/verify__verification_200_result_json_old_shape_strings.json new file mode 100644 index 0000000..d236164 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_200_result_json_old_shape_strings.json @@ -0,0 +1,72 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [], + "presumed_intent": "", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "sources": [ + { + "source_name": "", + "title": "", + "url": "https://old.example/a", + "snippet": "Old row.", + "date": "" + } + ], + "audit": { + "adjudication_summary": "", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "", + "score": null, + "reasoning": "", + "warnings": [] + } + ], + "debate_pro": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "debate_con": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "panel_agreement": "split" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_404.json b/tests/fixtures/parity/canonical/verify__verification_404.json new file mode 100644 index 0000000..f1a8c33 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_404.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_by_task_id_200.json b/tests/fixtures/parity/canonical/verify__verification_by_task_id_200.json new file mode 100644 index 0000000..e6d5f88 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_by_task_id_200.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_failed_409.json b/tests/fixtures/parity/canonical/verify__verification_failed_409.json new file mode 100644 index 0000000..b7c3f82 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_failed_409.json @@ -0,0 +1,23 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This check failed and has no result.", + "code": "verification_failed", + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "hint": "Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "failure": { + "code": "research_empty", + "detail": "No sources about the claim were found.", + "hint": null, + "failure_class": "insufficient_evidence", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_failed_409_not_a_claim_after_a_while.json b/tests/fixtures/parity/canonical/verify__verification_failed_409_not_a_claim_after_a_while.json new file mode 100644 index 0000000..9479d57 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_failed_409_not_a_claim_after_a_while.json @@ -0,0 +1,23 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This check failed and has no result.", + "code": "verification_failed", + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure": { + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_not_ready_409.json b/tests/fixtures/parity/canonical/verify__verification_not_ready_409.json new file mode 100644 index 0000000..d5ace3f --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_not_ready_409.json @@ -0,0 +1,15 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This check is still running.", + "code": "verification_not_ready", + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "hint": "Poll GET /verify/status/7cff18da2d979d6370e54a160be121ad until it completes, then read its result." + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_not_yours_404.json b/tests/fixtures/parity/canonical/verify__verification_not_yours_404.json new file mode 100644 index 0000000..f1a8c33 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_not_yours_404.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_public_anonymous.json b/tests/fixtures/parity/canonical/verify__verification_public_anonymous.json new file mode 100644 index 0000000..aec1fd3 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_public_anonymous.json @@ -0,0 +1,83 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "public", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": null + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_public_of_another_user.json b/tests/fixtures/parity/canonical/verify__verification_public_of_another_user.json new file mode 100644 index 0000000..4ccbda8 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_public_of_another_user.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "public", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_unknown_task_404.json b/tests/fixtures/parity/canonical/verify__verification_unknown_task_404.json new file mode 100644 index 0000000..e577e2e --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_unknown_task_404.json @@ -0,0 +1,13 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Not found.", + "code": "not_found", + "hint": "Unknown id. If this is a task_id, poll GET /verify/status/dddddddddddddddddddddddddddddddd for its status." + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_zero_retention_expired_410.json b/tests/fixtures/parity/canonical/verify__verification_zero_retention_expired_410.json new file mode 100644 index 0000000..010b258 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_zero_retention_expired_410.json @@ -0,0 +1,13 @@ +{ + "status": 410, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This verification is no longer available: its account removes verifications after a set period.", + "code": "purged", + "purged_at": "2026-10-01T09:07:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/verify__verification_zero_retention_served.json b/tests/fixtures/parity/canonical/verify__verification_zero_retention_served.json new file mode 100644 index 0000000..fca733d --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__verification_zero_retention_served.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical.", + "executive_summary": "The claim is well supported by evidence.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/canonical/webhook__certificate_timestamped.json b/tests/fixtures/parity/canonical/webhook__certificate_timestamped.json new file mode 100644 index 0000000..f2093db --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__certificate_timestamped.json @@ -0,0 +1,25 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "certificate.timestamped", + "verification_id": "68ca4aaf", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "batch_id": null, + "status": "completed", + "coverage": { + "status": "covered", + "reasons": [], + "certificate_id": "def7232d27eda03cf261569aee9948c5", + "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "as_of": "2026-09-03T10:00:00+00:00", + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:28:00.123456+00:00", + "event_id": "evt_0b92b443eb69b9c71434fdc6" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__certificate_timestamped_review_child.json b/tests/fixtures/parity/canonical/webhook__certificate_timestamped_review_child.json new file mode 100644 index 0000000..80582ef --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__certificate_timestamped_review_child.json @@ -0,0 +1,26 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "certificate.timestamped", + "verification_id": "68ca4aaf", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "batch_id": null, + "status": "completed", + "coverage": { + "status": "covered", + "reasons": [], + "certificate_id": "def7232d27eda03cf261569aee9948c5", + "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "as_of": "2026-09-03T10:00:00+00:00", + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + }, + "review_id": "d6b2bd72", + "attempt": 1, + "delivered_at": "2026-10-01T09:28:00.123456+00:00", + "event_id": "evt_0b92b443eb69b9c71434fdc6" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__citecheck_completed.json b/tests/fixtures/parity/canonical/webhook__citecheck_completed.json new file mode 100644 index 0000000..ce60399 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__citecheck_completed.json @@ -0,0 +1,133 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "citecheck.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "citecheck_id": "98c0e7d5", + "status": "completed", + "citecheck": { + "citecheck_id": "98c0e7d5", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T09:35:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 1 + }, + "credits": { + "charged": 2 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": { + "finding": "contradicted", + "source": "support", + "is_issue": true + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "contradicted", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [ + { + "citation_index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "finding": "contradicted", + "source": "support", + "snippet": "The source says so.", + "rationale": "The page states it.", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "failure": null + } + ], + "citation_failures": [], + "failure": null, + "more_citations": [] + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:42:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__citecheck_failed.json b/tests/fixtures/parity/canonical/webhook__citecheck_failed.json new file mode 100644 index 0000000..7474d1c --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__citecheck_failed.json @@ -0,0 +1,46 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "citecheck.failed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "citecheck_id": "98c0e7d5", + "status": "failed", + "citecheck": { + "citecheck_id": "98c0e7d5", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T09:35:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 20 + }, + "summary": { + "citations_found": null, + "citations_selected": null, + "citation_limit": 20, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [], + "citation_issues": [], + "citation_failures": [], + "failure": { + "failure_reason": "no_citations", + "failure_class": "invalid_input", + "retryable": false, + "hint": "The text has no citation to check: no link, DOI or numbered reference with one.", + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_citations": null + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:42:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__review_completed.json b/tests/fixtures/parity/canonical/webhook__review_completed.json new file mode 100644 index 0000000..78cf7d2 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__review_completed.json @@ -0,0 +1,155 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "review.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review_id": "8cb2f001", + "status": "completed", + "review": { + "review_id": "8cb2f001", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T09:35:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 1, + "completed": 1, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 11 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "8ceed6f0", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", + "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "5ccac77f53ff49328ec134fb29d66542", + "verification_id": "8ceed6f0", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T09:56:00.123456+00:00", + "modified_at": null, + "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", + "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "failure": null + }, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + }, + "attempt": 1, + "delivered_at": "2026-10-01T10:03:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__review_completed_key_default_url.json b/tests/fixtures/parity/canonical/webhook__review_completed_key_default_url.json new file mode 100644 index 0000000..0631d53 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__review_completed_key_default_url.json @@ -0,0 +1,104 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "review.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review_id": "8cb2f001", + "status": "completed", + "review": { + "review_id": "8cb2f001", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T09:35:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:42:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__review_completed_oversized_rebuilt.json b/tests/fixtures/parity/canonical/webhook__review_completed_oversized_rebuilt.json new file mode 100644 index 0000000..e96d947 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__review_completed_oversized_rebuilt.json @@ -0,0 +1,10 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "review.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review_id": "8cb2f001", + "status": "completed" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__review_failed.json b/tests/fixtures/parity/canonical/webhook__review_failed.json new file mode 100644 index 0000000..f382954 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__review_failed.json @@ -0,0 +1,72 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "review.failed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review_id": "8cb2f001", + "status": "failed", + "review": { + "review_id": "8cb2f001", + "view": "full", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T09:35:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": null, + "claim_limit": 20, + "claim_limit_reached": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": { + "failure_reason": "no_claim", + "failure_class": "invalid_input", + "retryable": false, + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:42:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_completed.json b/tests/fixtures/parity/canonical/webhook__verification_completed.json new file mode 100644 index 0000000..64c7f2c --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_completed.json @@ -0,0 +1,109 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.completed", + "event_id": "evt_0b92b443eb69b9c71434fdc6", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "verification_id": "68ca4aaf", + "batch_id": null, + "status": "completed", + "verification": { + "status": "completed", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "result": { + "verification_id": "68ca4aaf", + "claim": "The Eiffel Tower is in Berlin.", + "visibility": "private", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "presumed_intent": "Check where a landmark is.", + "verdict": "False", + "confidence": "high", + "lenz_score": 1, + "key_finding": "The Eiffel Tower is in Paris.", + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "warnings": [ + "Only two sources were found." + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "created_at": "2026-10-01T09:21:00.123456+00:00", + "sources": [ + { + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "date": "2025-01-15" + }, + { + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "date": "" + } + ], + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Evidence", + "score": 1.0, + "reasoning": "Both sources place the tower in Paris.", + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Evidence", + "score": 2.0, + "reasoning": "The encyclopedia entry is unambiguous.", + "warnings": [] + } + ], + "debate_pro": { + "role": "pro", + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable." + }, + "debate_con": { + "role": "con", + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + }, + "completed_at": "2026-10-01T09:21:00.123456+00:00" + } + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:28:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_completed_in_batch.json b/tests/fixtures/parity/canonical/webhook__verification_completed_in_batch.json new file mode 100644 index 0000000..f5a306c --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_completed_in_batch.json @@ -0,0 +1,109 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.completed", + "event_id": "evt_0b92b443eb69b9c71434fdc6", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "verification_id": "68ca4aaf", + "batch_id": "4ee0c3aa1b671eaa", + "status": "completed", + "verification": { + "status": "completed", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "result": { + "verification_id": "68ca4aaf", + "claim": "The Eiffel Tower is in Berlin.", + "visibility": "private", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "presumed_intent": "Check where a landmark is.", + "verdict": "False", + "confidence": "high", + "lenz_score": 1, + "key_finding": "The Eiffel Tower is in Paris.", + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "warnings": [ + "Only two sources were found." + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "created_at": "2026-10-01T09:28:00.123456+00:00", + "sources": [ + { + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "date": "2025-01-15" + }, + { + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "date": "" + } + ], + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Evidence", + "score": 1.0, + "reasoning": "Both sources place the tower in Paris.", + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Evidence", + "score": 2.0, + "reasoning": "The encyclopedia entry is unambiguous.", + "warnings": [] + } + ], + "debate_pro": { + "role": "pro", + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable." + }, + "debate_con": { + "role": "con", + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + }, + "completed_at": "2026-10-01T09:28:00.123456+00:00" + } + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:35:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..2bbe988 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,109 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.completed", + "event_id": "evt_0b92b443eb69b9c71434fdc6", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "verification_id": "68ca4aaf", + "batch_id": null, + "status": "completed", + "verification": { + "status": "completed", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "result": { + "verification_id": "68ca4aaf", + "claim": "The Eiffel Tower is in Berlin.", + "visibility": "private", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "presumed_intent": "Check where a landmark is.", + "verdict": "False", + "confidence": "high", + "lenz_score": 1, + "key_finding": "The Eiffel Tower is in Paris.", + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "warnings": [ + "Only two sources were found." + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "created_at": "2026-10-01T23:55:00.123456+00:00", + "sources": [ + { + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "date": "2025-01-15" + }, + { + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "date": "" + } + ], + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Evidence", + "score": 1.0, + "reasoning": "Both sources place the tower in Paris.", + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Evidence", + "score": 2.0, + "reasoning": "The encyclopedia entry is unambiguous.", + "warnings": [] + } + ], + "debate_pro": { + "role": "pro", + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable." + }, + "debate_con": { + "role": "con", + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + }, + "completed_at": "2026-10-02T00:03:00.123456+00:00" + } + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:35:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..fa61911 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_same_day_hours_apart.json @@ -0,0 +1,109 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.completed", + "event_id": "evt_0b92b443eb69b9c71434fdc6", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "verification_id": "68ca4aaf", + "batch_id": null, + "status": "completed", + "verification": { + "status": "completed", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "result": { + "verification_id": "68ca4aaf", + "claim": "The Eiffel Tower is in Berlin.", + "visibility": "private", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "presumed_intent": "Check where a landmark is.", + "verdict": "False", + "confidence": "high", + "lenz_score": 1, + "key_finding": "The Eiffel Tower is in Paris.", + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "warnings": [ + "Only two sources were found." + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "created_at": "2026-10-01T08:00:00.123456+00:00", + "sources": [ + { + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "date": "2025-01-15" + }, + { + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "date": "" + } + ], + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Evidence", + "score": 1.0, + "reasoning": "Both sources place the tower in Paris.", + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Evidence", + "score": 2.0, + "reasoning": "The encyclopedia entry is unambiguous.", + "warnings": [] + } + ], + "debate_pro": { + "role": "pro", + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable." + }, + "debate_con": { + "role": "con", + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + }, + "completed_at": "2026-10-01T20:00:00.123456+00:00" + } + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:28:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_failed_insufficient_evidence.json b/tests/fixtures/parity/canonical/webhook__verification_failed_insufficient_evidence.json new file mode 100644 index 0000000..f47e7ee --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_failed_insufficient_evidence.json @@ -0,0 +1,26 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.failed", + "event_id": "evt_7cff18da2d979d6370e54a16", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": null, + "batch_id": null, + "status": "failed", + "verification": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "research_insufficient", + "detail": "A sentence on what happened.", + "hint": null, + "failure_class": "insufficient_evidence", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors" + } + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:14:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_failed_not_a_claim.json b/tests/fixtures/parity/canonical/webhook__verification_failed_not_a_claim.json new file mode 100644 index 0000000..cf284d5 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_failed_not_a_claim.json @@ -0,0 +1,26 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.failed", + "event_id": "evt_7cff18da2d979d6370e54a16", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": null, + "batch_id": null, + "status": "failed", + "verification": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "no_checkable_claim", + "detail": "A sentence on what happened.", + "hint": null, + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors" + } + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:14:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_failed_upstream_unavailable.json b/tests/fixtures/parity/canonical/webhook__verification_failed_upstream_unavailable.json new file mode 100644 index 0000000..322b4ba --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_failed_upstream_unavailable.json @@ -0,0 +1,26 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.failed", + "event_id": "evt_7cff18da2d979d6370e54a16", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": null, + "batch_id": null, + "status": "failed", + "verification": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "framing_failed", + "detail": "A sentence on what happened.", + "hint": null, + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors" + } + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:14:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_needs_input_multi_claim.json b/tests/fixtures/parity/canonical/webhook__verification_needs_input_multi_claim.json new file mode 100644 index 0000000..0961dbb --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_needs_input_multi_claim.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.needs_input", + "event_id": "evt_7cff18da2d979d6370e54a16", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": null, + "batch_id": null, + "status": "needs_input", + "verification": { + "status": "needs_input", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "reason": "multi_claim", + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.", + "claims": [ + { + "claim": "The Earth is round.", + "domain": "" + }, + { + "claim": "The Moon is made of cheese.", + "domain": "Science" + } + ] + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:14:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/expected/account__library_empty.json b/tests/fixtures/parity/expected/account__library_empty.json new file mode 100644 index 0000000..d628806 --- /dev/null +++ b/tests/fixtures/parity/expected/account__library_empty.json @@ -0,0 +1,9 @@ +{ + "dump": { + "items": [], + "page": 1, + "page_size": 20, + "total": 0 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/account__library_item_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/account__library_item_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..dedd58d --- /dev/null +++ b/tests/fixtures/parity/expected/account__library_item_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,25 @@ +{ + "dump": { + "items": [ + { + "claim": "A library claim.", + "confidence": "low", + "created_at": "2026-10-01T23:55:00.123456+00:00", + "domain": "", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + } + ], + "page": 1, + "page_size": 20, + "total": 1 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/account__library_item_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/account__library_item_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..7edcd92 --- /dev/null +++ b/tests/fixtures/parity/expected/account__library_item_modified_at_same_day_hours_apart.json @@ -0,0 +1,25 @@ +{ + "dump": { + "items": [ + { + "claim": "A library claim.", + "confidence": "low", + "created_at": "2026-10-01T08:00:00.123456+00:00", + "domain": "", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + } + ], + "page": 1, + "page_size": 20, + "total": 1 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/account__library_items.json b/tests/fixtures/parity/expected/account__library_items.json new file mode 100644 index 0000000..72a7d37 --- /dev/null +++ b/tests/fixtures/parity/expected/account__library_items.json @@ -0,0 +1,55 @@ +{ + "dump": { + "items": [ + { + "claim": "Library claim 0.", + "confidence": "low", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + }, + { + "claim": "Library claim 1.", + "confidence": "low", + "created_at": "2026-10-01T09:28:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "7c83247c" + }, + { + "claim": "Library claim 2.", + "confidence": "low", + "created_at": "2026-10-01T09:42:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "b79019e4" + } + ], + "page": 1, + "page_size": 20, + "total": 3 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/account__library_no_match.json b/tests/fixtures/parity/expected/account__library_no_match.json new file mode 100644 index 0000000..d628806 --- /dev/null +++ b/tests/fixtures/parity/expected/account__library_no_match.json @@ -0,0 +1,9 @@ +{ + "dump": { + "items": [], + "page": 1, + "page_size": 20, + "total": 0 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/account__library_page_past_end.json b/tests/fixtures/parity/expected/account__library_page_past_end.json new file mode 100644 index 0000000..437be04 --- /dev/null +++ b/tests/fixtures/parity/expected/account__library_page_past_end.json @@ -0,0 +1,9 @@ +{ + "dump": { + "items": [], + "page": 2, + "page_size": 20, + "total": 1 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/account__library_paginated_second_page.json b/tests/fixtures/parity/expected/account__library_paginated_second_page.json new file mode 100644 index 0000000..6d4d3d3 --- /dev/null +++ b/tests/fixtures/parity/expected/account__library_paginated_second_page.json @@ -0,0 +1,40 @@ +{ + "dump": { + "items": [ + { + "claim": "Paged claim 020.", + "confidence": "low", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "domain": "", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + }, + { + "claim": "Paged claim 021.", + "confidence": "low", + "created_at": "2026-10-01T09:28:00.123456+00:00", + "domain": "", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "7c83247c" + } + ], + "page": 2, + "page_size": 20, + "total": 22 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/account__me_usage_extra_credits.json b/tests/fixtures/parity/expected/account__me_usage_extra_credits.json new file mode 100644 index 0000000..4b02079 --- /dev/null +++ b/tests/fixtures/parity/expected/account__me_usage_extra_credits.json @@ -0,0 +1,62 @@ +{ + "dump": { + "ask": { + "bonus": 250, + "credits": 250, + "quota_remaining": 350, + "quota_total": 350, + "quota_used": 0, + "remaining": 350 + }, + "assess": { + "bonus": 250, + "credits": 250, + "quota_remaining": 350, + "quota_total": 350, + "quota_used": 0, + "remaining": 350 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 250, + "extra": 250, + "remaining": 350, + "resets_at": "2026-10-01T09:07:00+00:00", + "total": 350, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "verify": { + "bonus": 25, + "credits": 25, + "quota_remaining": 35, + "quota_total": 35, + "quota_used": 0, + "remaining": 35 + } + }, + "render": "Lenz usage (Free plan)\n 350 credits left (≈ 35 verifications · 350 assessments)\n Verify: 35 left (0 / 35 quota + 25 extra · 10 credits each · 5 at depth \"low\")\n Ask: 350 left (0 / 350 quota + 250 extra · 1 credit each)\n Assess: 350 left (0 / 350 quota + 250 extra · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 350,\n \"used\": 0,\n \"remaining\": 350,\n \"extra\": 250,\n \"bonus\": 250,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 35,\n \"quota_remaining\": 35,\n \"bonus\": 25,\n \"credits\": 25,\n \"remaining\": 35\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 350,\n \"quota_remaining\": 350,\n \"bonus\": 250,\n \"credits\": 250,\n \"remaining\": 350\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 350,\n \"quota_remaining\": 350,\n \"bonus\": 250,\n \"credits\": 250,\n \"remaining\": 350\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" +} diff --git a/tests/fixtures/parity/expected/account__me_usage_extra_only.json b/tests/fixtures/parity/expected/account__me_usage_extra_only.json new file mode 100644 index 0000000..fbd9a1f --- /dev/null +++ b/tests/fixtures/parity/expected/account__me_usage_extra_only.json @@ -0,0 +1,62 @@ +{ + "dump": { + "ask": { + "bonus": 37, + "credits": 37, + "quota_remaining": 37, + "quota_total": 137, + "quota_used": 100, + "remaining": 37 + }, + "assess": { + "bonus": 37, + "credits": 37, + "quota_remaining": 37, + "quota_total": 137, + "quota_used": 100, + "remaining": 37 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 37, + "extra": 37, + "remaining": 37, + "resets_at": "2026-10-01T09:07:00+00:00", + "total": 137, + "used": 100 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "verify": { + "bonus": 3, + "credits": 3, + "quota_remaining": 3, + "quota_total": 13, + "quota_used": 10, + "remaining": 3 + } + }, + "render": "Lenz usage (Free plan)\n 37 credits left (≈ 3 verifications · 37 assessments)\n Verify: 3 left (10 / 13 quota + 3 extra · 10 credits each · 5 at depth \"low\")\n Ask: 37 left (100 / 137 quota + 37 extra · 1 credit each)\n Assess: 37 left (100 / 137 quota + 37 extra · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 137,\n \"used\": 100,\n \"remaining\": 37,\n \"extra\": 37,\n \"bonus\": 37,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 10,\n \"quota_total\": 13,\n \"quota_remaining\": 3,\n \"bonus\": 3,\n \"credits\": 3,\n \"remaining\": 3\n },\n \"ask\": {\n \"quota_used\": 100,\n \"quota_total\": 137,\n \"quota_remaining\": 37,\n \"bonus\": 37,\n \"credits\": 37,\n \"remaining\": 37\n },\n \"assess\": {\n \"quota_used\": 100,\n \"quota_total\": 137,\n \"quota_remaining\": 37,\n \"bonus\": 37,\n \"credits\": 37,\n \"remaining\": 37\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" +} diff --git a/tests/fixtures/parity/expected/account__me_usage_extract_calls.json b/tests/fixtures/parity/expected/account__me_usage_extract_calls.json new file mode 100644 index 0000000..cfb8de5 --- /dev/null +++ b/tests/fixtures/parity/expected/account__me_usage_extract_calls.json @@ -0,0 +1,62 @@ +{ + "dump": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 100, + "resets_at": "2026-10-01T09:07:00+00:00", + "total": 100, + "used": 0 + }, + "extract": { + "calls_today": 7, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 10, + "quota_total": 10, + "quota_used": 0, + "remaining": 10 + } + }, + "render": "Lenz usage (Free plan)\n 100 credits left (≈ 10 verifications · 100 assessments)\n Verify: 10 left (0 / 10 quota · 10 credits each · 5 at depth \"low\")\n Ask: 100 left (0 / 100 quota · 1 credit each)\n Assess: 100 left (0 / 100 quota · 1 credit each)\n Extract: 7 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 0,\n \"remaining\": 100,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 10,\n \"quota_remaining\": 10,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 10\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"extract\": {\n \"calls_today\": 7,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" +} diff --git a/tests/fixtures/parity/expected/account__me_usage_free.json b/tests/fixtures/parity/expected/account__me_usage_free.json new file mode 100644 index 0000000..5d7b08d --- /dev/null +++ b/tests/fixtures/parity/expected/account__me_usage_free.json @@ -0,0 +1,62 @@ +{ + "dump": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 100, + "resets_at": "2026-10-01T09:07:00+00:00", + "total": 100, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 10, + "quota_total": 10, + "quota_used": 0, + "remaining": 10 + } + }, + "render": "Lenz usage (Free plan)\n 100 credits left (≈ 10 verifications · 100 assessments)\n Verify: 10 left (0 / 10 quota · 10 credits each · 5 at depth \"low\")\n Ask: 100 left (0 / 100 quota · 1 credit each)\n Assess: 100 left (0 / 100 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 0,\n \"remaining\": 100,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 10,\n \"quota_remaining\": 10,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 10\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" +} diff --git a/tests/fixtures/parity/expected/account__me_usage_free_partly_spent.json b/tests/fixtures/parity/expected/account__me_usage_free_partly_spent.json new file mode 100644 index 0000000..61b0e4c --- /dev/null +++ b/tests/fixtures/parity/expected/account__me_usage_free_partly_spent.json @@ -0,0 +1,62 @@ +{ + "dump": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 83, + "quota_total": 100, + "quota_used": 17, + "remaining": 83 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 83, + "quota_total": 100, + "quota_used": 17, + "remaining": 83 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 83, + "resets_at": "2026-10-01T09:07:00+00:00", + "total": 100, + "used": 17 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 8, + "quota_total": 10, + "quota_used": 2, + "remaining": 8 + } + }, + "render": "Lenz usage (Free plan)\n 83 credits left (≈ 8 verifications · 83 assessments)\n Verify: 8 left (2 / 10 quota · 10 credits each · 5 at depth \"low\")\n Ask: 83 left (17 / 100 quota · 1 credit each)\n Assess: 83 left (17 / 100 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 17,\n \"remaining\": 83,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 2,\n \"quota_total\": 10,\n \"quota_remaining\": 8,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 8\n },\n \"ask\": {\n \"quota_used\": 17,\n \"quota_total\": 100,\n \"quota_remaining\": 83,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 83\n },\n \"assess\": {\n \"quota_used\": 17,\n \"quota_total\": 100,\n \"quota_remaining\": 83,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 83\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" +} diff --git a/tests/fixtures/parity/expected/account__me_usage_plus.json b/tests/fixtures/parity/expected/account__me_usage_plus.json new file mode 100644 index 0000000..240dcb2 --- /dev/null +++ b/tests/fixtures/parity/expected/account__me_usage_plus.json @@ -0,0 +1,62 @@ +{ + "dump": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 500, + "quota_total": 500, + "quota_used": 0, + "remaining": 500 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 500, + "quota_total": 500, + "quota_used": 0, + "remaining": 500 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 500, + "resets_at": "2026-10-01T09:07:00.123456+00:00", + "total": 500, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "plus", + "plan_label": "Plus", + "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 50, + "quota_total": 50, + "quota_used": 0, + "remaining": 50 + } + }, + "render": "Lenz usage (Plus plan)\n 500 credits left (≈ 50 verifications · 500 assessments)\n Verify: 50 left (0 / 50 quota · 10 credits each · 5 at depth \"low\")\n Ask: 500 left (0 / 500 quota · 1 credit each)\n Assess: 500 left (0 / 500 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", + "render_json": "{\n \"plan\": \"plus\",\n \"plan_label\": \"Plus\",\n \"quota_resets_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"credits\": {\n \"total\": 500,\n \"used\": 0,\n \"remaining\": 500,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00.123456+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 50,\n \"quota_remaining\": 50,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 50\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 500,\n \"quota_remaining\": 500,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 500\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 500,\n \"quota_remaining\": 500,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 500\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" +} diff --git a/tests/fixtures/parity/expected/account__me_usage_pro.json b/tests/fixtures/parity/expected/account__me_usage_pro.json new file mode 100644 index 0000000..6bd10f7 --- /dev/null +++ b/tests/fixtures/parity/expected/account__me_usage_pro.json @@ -0,0 +1,62 @@ +{ + "dump": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 5000, + "quota_total": 5000, + "quota_used": 0, + "remaining": 5000 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 5000, + "quota_total": 5000, + "quota_used": 0, + "remaining": 5000 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 5000, + "resets_at": "2026-10-01T09:07:00.123456+00:00", + "total": 5000, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "pro", + "plan_label": "Pro", + "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 500, + "quota_total": 500, + "quota_used": 0, + "remaining": 500 + } + }, + "render": "Lenz usage (Pro plan)\n 5000 credits left (≈ 500 verifications · 5000 assessments)\n Verify: 500 left (0 / 500 quota · 10 credits each · 5 at depth \"low\")\n Ask: 5000 left (0 / 5000 quota · 1 credit each)\n Assess: 5000 left (0 / 5000 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", + "render_json": "{\n \"plan\": \"pro\",\n \"plan_label\": \"Pro\",\n \"quota_resets_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"credits\": {\n \"total\": 5000,\n \"used\": 0,\n \"remaining\": 5000,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00.123456+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 500,\n \"quota_remaining\": 500,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 500\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 5000,\n \"quota_remaining\": 5000,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 5000\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 5000,\n \"quota_remaining\": 5000,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 5000\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" +} diff --git a/tests/fixtures/parity/expected/account__me_usage_pro_extra.json b/tests/fixtures/parity/expected/account__me_usage_pro_extra.json new file mode 100644 index 0000000..ca22ae7 --- /dev/null +++ b/tests/fixtures/parity/expected/account__me_usage_pro_extra.json @@ -0,0 +1,62 @@ +{ + "dump": { + "ask": { + "bonus": 1000, + "credits": 1000, + "quota_remaining": 6000, + "quota_total": 6000, + "quota_used": 0, + "remaining": 6000 + }, + "assess": { + "bonus": 1000, + "credits": 1000, + "quota_remaining": 6000, + "quota_total": 6000, + "quota_used": 0, + "remaining": 6000 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 1000, + "extra": 1000, + "remaining": 6000, + "resets_at": "2026-10-01T09:07:00.123456+00:00", + "total": 6000, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "pro", + "plan_label": "Pro", + "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "verify": { + "bonus": 100, + "credits": 100, + "quota_remaining": 600, + "quota_total": 600, + "quota_used": 0, + "remaining": 600 + } + }, + "render": "Lenz usage (Pro plan)\n 6000 credits left (≈ 600 verifications · 6000 assessments)\n Verify: 600 left (0 / 600 quota + 100 extra · 10 credits each · 5 at depth \"low\")\n Ask: 6000 left (0 / 6000 quota + 1000 extra · 1 credit each)\n Assess: 6000 left (0 / 6000 quota + 1000 extra · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", + "render_json": "{\n \"plan\": \"pro\",\n \"plan_label\": \"Pro\",\n \"quota_resets_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"credits\": {\n \"total\": 6000,\n \"used\": 0,\n \"remaining\": 6000,\n \"extra\": 1000,\n \"bonus\": 1000,\n \"resets_at\": \"2026-10-01T09:07:00.123456+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 600,\n \"quota_remaining\": 600,\n \"bonus\": 100,\n \"credits\": 100,\n \"remaining\": 600\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 6000,\n \"quota_remaining\": 6000,\n \"bonus\": 1000,\n \"credits\": 1000,\n \"remaining\": 6000\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 6000,\n \"quota_remaining\": 6000,\n \"bonus\": 1000,\n \"credits\": 1000,\n \"remaining\": 6000\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" +} diff --git a/tests/fixtures/parity/expected/account__me_usage_stale_quota_row.json b/tests/fixtures/parity/expected/account__me_usage_stale_quota_row.json new file mode 100644 index 0000000..5d7b08d --- /dev/null +++ b/tests/fixtures/parity/expected/account__me_usage_stale_quota_row.json @@ -0,0 +1,62 @@ +{ + "dump": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 100, + "resets_at": "2026-10-01T09:07:00+00:00", + "total": 100, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 10, + "quota_total": 10, + "quota_used": 0, + "remaining": 10 + } + }, + "render": "Lenz usage (Free plan)\n 100 credits left (≈ 10 verifications · 100 assessments)\n Verify: 10 left (0 / 10 quota · 10 credits each · 5 at depth \"low\")\n Ask: 100 left (0 / 100 quota · 1 credit each)\n Assess: 100 left (0 / 100 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 0,\n \"remaining\": 100,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 10,\n \"quota_remaining\": 10,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 10\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__401_no_key.json b/tests/fixtures/parity/expected/assess__401_no_key.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/assess__401_no_key.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/assess__402_no_credits.json b/tests/fixtures/parity/expected/assess__402_no_credits.json new file mode 100644 index 0000000..732bc39 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__402_no_credits.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "No remaining /assess units.", + "code": "no_credits", + "cost": 1, + "credit_balance": 0, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "No remaining /assess units.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "No remaining /assess units.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "No remaining /assess units.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 0, + "request_id": "", + "requested": null, + "resets_at": "2026-10-01T09:14:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/assess__422_blank_item.json b/tests/fixtures/parity/expected/assess__422_blank_item.json new file mode 100644 index 0000000..4b35c85 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__422_blank_item.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "claims[1] is blank.", + "code": "blank_item", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "claims[1] is blank.\n Fix: Check the request body against the OpenAPI spec.", + "message": "claims[1] is blank.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "claims[1] is blank.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/assess__422_blank_text.json b/tests/fixtures/parity/expected/assess__422_blank_text.json new file mode 100644 index 0000000..872ff11 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__422_blank_text.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Text is required.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Text is required.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Text is required.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Text is required.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/assess__422_input_conflict.json b/tests/fixtures/parity/expected/assess__422_input_conflict.json new file mode 100644 index 0000000..215d4af --- /dev/null +++ b/tests/fixtures/parity/expected/assess__422_input_conflict.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Send either `claim` (one text) or `claims` (a list of claims), not both.", + "code": "input_conflict", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Send either `claim` (one text) or `claims` (a list of claims), not both.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Send either `claim` (one text) or `claims` (a list of claims), not both.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Send either `claim` (one text) or `claims` (a list of claims), not both.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/assess__422_item_too_long.json b/tests/fixtures/parity/expected/assess__422_item_too_long.json new file mode 100644 index 0000000..1e678c0 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__422_item_too_long.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "claims[1] is 2001 characters; each claim may be at most 2000. Send a document to /extract first, then assess its claims.", + "code": "item_too_long", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "claims[1] is 2001 characters; each claim may be at most 2000. Send a document to /extract first, then assess its claims.\n Fix: Check the request body against the OpenAPI spec.", + "message": "claims[1] is 2001 characters; each claim may be at most 2000. Send a document to /extract first, then assess its claims.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "claims[1] is 2001 characters; each claim may be at most 2000. Send a document to /extract first, then assess its claims.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/assess__422_no_input_field.json b/tests/fixtures/parity/expected/assess__422_no_input_field.json new file mode 100644 index 0000000..6760d1a --- /dev/null +++ b/tests/fixtures/parity/expected/assess__422_no_input_field.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/assess__422_too_many_items.json b/tests/fixtures/parity/expected/assess__422_too_many_items.json new file mode 100644 index 0000000..14bdc66 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__422_too_many_items.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "At most 20 claims per call; got 21. Split the list.", + "code": "too_many_items", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "At most 20 claims per call; got 21. Split the list.\n Fix: Check the request body against the OpenAPI spec.", + "message": "At most 20 claims per call; got 21. Split the list.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "At most 20 claims per call; got 21. Split the list.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/assess__422_wrong_type_claim.json b/tests/fixtures/parity/expected/assess__422_wrong_type_claim.json new file mode 100644 index 0000000..45b3d77 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__422_wrong_type_claim.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "[{'type': 'string_type', 'loc': ['body', 'payload', 'claim'], 'msg': 'Input should be a valid string'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "claim" + ], + "msg": "Input should be a valid string", + "type": "string_type" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'string_type', 'loc': ['body', 'payload', 'claim'], 'msg': 'Input should be a valid string'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'string_type', 'loc': ['body', 'payload', 'claim'], 'msg': 'Input should be a valid string'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'string_type', 'loc': ['body', 'payload', 'claim'], 'msg': 'Input should be a valid string'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/assess__422_wrong_type_claims.json b/tests/fixtures/parity/expected/assess__422_wrong_type_claims.json new file mode 100644 index 0000000..7713b4c --- /dev/null +++ b/tests/fixtures/parity/expected/assess__422_wrong_type_claims.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "[{'type': 'list_type', 'loc': ['body', 'payload', 'claims'], 'msg': 'Input should be a valid list'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "claims" + ], + "msg": "Input should be a valid list", + "type": "list_type" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'list_type', 'loc': ['body', 'payload', 'claims'], 'msg': 'Input should be a valid list'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'list_type', 'loc': ['body', 'payload', 'claims'], 'msg': 'Input should be a valid list'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'list_type', 'loc': ['body', 'payload', 'claims'], 'msg': 'Input should be a valid list'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/assess__502_framing_failed.json b/tests/fixtures/parity/expected/assess__502_framing_failed.json new file mode 100644 index 0000000..c8d0b2d --- /dev/null +++ b/tests/fixtures/parity/expected/assess__502_framing_failed.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Framing failed", + "code": "framing_failed", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Framing failed\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Framing failed", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Framing failed", + "status": 502 + } + }, + "request_id": "", + "retry_after": null, + "status_code": 502, + "type": "LenzAPIError" + } +} diff --git a/tests/fixtures/parity/expected/assess__503_capacity.json b/tests/fixtures/parity/expected/assess__503_capacity.json new file mode 100644 index 0000000..017e2bc --- /dev/null +++ b/tests/fixtures/parity/expected/assess__503_capacity.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 100, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/assess__503_list_all_upstream_unavailable.json b/tests/fixtures/parity/expected/assess__503_list_all_upstream_unavailable.json new file mode 100644 index 0000000..b61a2fb --- /dev/null +++ b/tests/fixtures/parity/expected/assess__503_list_all_upstream_unavailable.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Our model providers are temporarily unavailable. Please retry shortly. Nothing was charged.", + "code": "upstream_unavailable", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Our model providers are temporarily unavailable. Please retry shortly. Nothing was charged.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Our model providers are temporarily unavailable. Please retry shortly. Nothing was charged.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Our model providers are temporarily unavailable. Please retry shortly. Nothing was charged.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 90, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/assess__503_upstream_unavailable.json b/tests/fixtures/parity/expected/assess__503_upstream_unavailable.json new file mode 100644 index 0000000..7553c4c --- /dev/null +++ b/tests/fixtures/parity/expected/assess__503_upstream_unavailable.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Our model providers are temporarily unavailable. Please retry shortly.", + "code": "upstream_unavailable", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Our model providers are temporarily unavailable. Please retry shortly.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Our model providers are temporarily unavailable. Please retry shortly.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Our model providers are temporarily unavailable. Please retry shortly.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 90, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/assess__deep_tier_hit.json b/tests/fixtures/parity/expected/assess__deep_tier_hit.json new file mode 100644 index 0000000..89424ff --- /dev/null +++ b/tests/fixtures/parity/expected/assess__deep_tier_hit.json @@ -0,0 +1,26 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "Water boils at 100C.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": "The claim is verified.", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": "https://lenz.io/api/v1/verifications/f3436f50" + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "True (high) — Water boils at 100C.\n The claim is verified.\n ask follow-ups: lenz ask f3436f50 \"\"\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Water boils at 100C.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": \"https://lenz.io/api/v1/verifications/f3436f50\",\n \"rationale\": \"The claim is verified.\",\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__idempotency_body_mismatch.json b/tests/fixtures/parity/expected/assess__idempotency_body_mismatch.json new file mode 100644 index 0000000..989af48 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__idempotency_body_mismatch.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Idempotency-Key reused with a different request body.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Idempotency-Key reused with a different request body.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/assess__idempotency_first.json b/tests/fixtures/parity/expected/assess__idempotency_first.json new file mode 100644 index 0000000..cb3d6d5 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__idempotency_first.json @@ -0,0 +1,26 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "The Earth orbits the Sun.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "True (high) — The Earth orbits the Sun.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Earth orbits the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__idempotency_replay.json b/tests/fixtures/parity/expected/assess__idempotency_replay.json new file mode 100644 index 0000000..cb3d6d5 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__idempotency_replay.json @@ -0,0 +1,26 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "The Earth orbits the Sun.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "True (high) — The Earth orbits the Sun.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Earth orbits the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__list_all_error_rows.json b/tests/fixtures/parity/expected/assess__list_all_error_rows.json new file mode 100644 index 0000000..edf8955 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__list_all_error_rows.json @@ -0,0 +1,40 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "hi", + "confidence": "low", + "dissent": null, + "error_code": "no_claim", + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.", + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Error", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "hello", + "confidence": "low", + "dissent": null, + "error_code": "no_claim", + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.", + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Error", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "Error (no_claim) — hi\n The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\nError (no_claim) — hello\n The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"hi\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\"\n },\n {\n \"claim\": \"hello\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\"\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__list_compound_item.json b/tests/fixtures/parity/expected/assess__list_compound_item.json new file mode 100644 index 0000000..6437e79 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__list_compound_item.json @@ -0,0 +1,43 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "Primary claim.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": "Assessed the main claim only. Send identified_claims as their own items to check the rest.", + "identified_claims": [ + "Second claim.", + "Third claim." + ], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Mostly False", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "A plain claim.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Mostly False", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "Mostly False (high) — Primary claim.\n also found:\n • Second claim.\n • Third claim.\n Assessed the main claim only. Send identified_claims as their own items to check the rest.\nMostly False (high) — A plain claim.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Primary claim.\",\n \"language\": \"en\",\n \"verdict\": \"Mostly False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [\n \"Second claim.\",\n \"Third claim.\"\n ],\n \"hint\": \"Assessed the main claim only. Send identified_claims as their own items to check the rest.\"\n },\n {\n \"claim\": \"A plain claim.\",\n \"language\": \"en\",\n \"verdict\": \"Mostly False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__list_mixed_rows.json b/tests/fixtures/parity/expected/assess__list_mixed_rows.json new file mode 100644 index 0000000..f92df93 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__list_mixed_rows.json @@ -0,0 +1,68 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "Water boils at 100 C at sea level.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "hello there", + "confidence": "low", + "dissent": null, + "error_code": "no_claim", + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.", + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Error", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "vendor is down", + "confidence": "low", + "dissent": null, + "error_code": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Error", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "cannot frame", + "confidence": "low", + "dissent": null, + "error_code": "framing_failed", + "hint": "This item could not be processed; retrying it as-is will not help. Send it rephrased as one factual statement; nothing was charged.", + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Error", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "True (high) — Water boils at 100 C at sea level.\nError (no_claim) — hello there\n The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\nError (upstream_unavailable) — vendor is down\n A model provider was unavailable for this item. Retry it; nothing was charged.\nError (framing_failed) — cannot frame\n This item could not be processed; retrying it as-is will not help. Send it rephrased as one factual statement; \nnothing was charged.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Water boils at 100 C at sea level.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"hello there\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\"\n },\n {\n \"claim\": \"vendor is down\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"upstream_unavailable\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"A model provider was unavailable for this item. Retry it; nothing was charged.\"\n },\n {\n \"claim\": \"cannot frame\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"framing_failed\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"This item could not be processed; retrying it as-is will not help. Send it rephrased as one factual statement; nothing was charged.\"\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__memo_hit.json b/tests/fixtures/parity/expected/assess__memo_hit.json new file mode 100644 index 0000000..df5db6d --- /dev/null +++ b/tests/fixtures/parity/expected/assess__memo_hit.json @@ -0,0 +1,26 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "The Danube flows through Vienna.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": "The river runs through the city.", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "True (high) — The Danube flows through Vienna.\n The river runs through the city.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Danube flows through Vienna.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"The river runs through the city.\",\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__replay_later_200.json b/tests/fixtures/parity/expected/assess__replay_later_200.json new file mode 100644 index 0000000..cb3d6d5 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__replay_later_200.json @@ -0,0 +1,26 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "The Earth orbits the Sun.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "True (high) — The Earth orbits the Sun.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Earth orbits the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__single_no_claim.json b/tests/fixtures/parity/expected/assess__single_no_claim.json new file mode 100644 index 0000000..2c5225e --- /dev/null +++ b/tests/fixtures/parity/expected/assess__single_no_claim.json @@ -0,0 +1,11 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [], + "error": "No verifiable claim detected", + "error_code": "no_claim", + "more_claims": [] + }, + "render": "No claim found.\n", + "render_json": "{\n \"claims\": [],\n \"error\": \"No verifiable claim detected\",\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__single_one_claim.json b/tests/fixtures/parity/expected/assess__single_one_claim.json new file mode 100644 index 0000000..6a00522 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__single_one_claim.json @@ -0,0 +1,26 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "The registry reported 4,200 filings in 2024.", + "confidence": "high", + "dissent": "The registry figure is provisional, so the 2024 total cannot yet be confirmed.", + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": "The registry lists 4,200 filings for 2024 and has not revised the figure.", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "True (high) — The registry reported 4,200 filings in 2024.\n The registry lists 4,200 filings for 2024 and has not revised the figure.\n One reviewer disagreed: The registry figure is provisional, so the 2024 total cannot yet be confirmed.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The registry reported 4,200 filings in 2024.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"The registry lists 4,200 filings for 2024 and has not revised the figure.\",\n \"dissent\": \"The registry figure is provisional, so the 2024 total cannot yet be confirmed.\",\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__single_text_over_wave_more_claims.json b/tests/fixtures/parity/expected/assess__single_text_over_wave_more_claims.json new file mode 100644 index 0000000..519a6b2 --- /dev/null +++ b/tests/fixtures/parity/expected/assess__single_text_over_wave_more_claims.json @@ -0,0 +1,295 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "Claim number 0 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 1 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 2 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 3 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 4 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 5 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 6 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 7 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 8 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 9 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 10 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 11 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 12 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 13 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 14 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 15 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 16 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 17 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 18 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 19 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [ + "Claim number 20 is documented.", + "Claim number 21 is documented." + ] + }, + "render": "True (high) — Claim number 0 is documented.\nTrue (high) — Claim number 1 is documented.\nTrue (high) — Claim number 2 is documented.\nTrue (high) — Claim number 3 is documented.\nTrue (high) — Claim number 4 is documented.\nTrue (high) — Claim number 5 is documented.\nTrue (high) — Claim number 6 is documented.\nTrue (high) — Claim number 7 is documented.\nTrue (high) — Claim number 8 is documented.\nTrue (high) — Claim number 9 is documented.\nTrue (high) — Claim number 10 is documented.\nTrue (high) — Claim number 11 is documented.\nTrue (high) — Claim number 12 is documented.\nTrue (high) — Claim number 13 is documented.\nTrue (high) — Claim number 14 is documented.\nTrue (high) — Claim number 15 is documented.\nTrue (high) — Claim number 16 is documented.\nTrue (high) — Claim number 17 is documented.\nTrue (high) — Claim number 18 is documented.\nTrue (high) — Claim number 19 is documented.\n\nNot checked (2 more claims found; pass them to `lenz assess`, 20 a call):\n • Claim number 20 is documented.\n • Claim number 21 is documented.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Claim number 0 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 1 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 2 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 3 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 4 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 5 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 6 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 7 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 8 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 9 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 10 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 11 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 12 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 13 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 14 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 15 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 16 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 17 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 18 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 19 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": [\n \"Claim number 20 is documented.\",\n \"Claim number 21 is documented.\"\n ]\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__single_text_several_claims.json b/tests/fixtures/parity/expected/assess__single_text_several_claims.json new file mode 100644 index 0000000..62e14ad --- /dev/null +++ b/tests/fixtures/parity/expected/assess__single_text_several_claims.json @@ -0,0 +1,54 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "Water boils at 100 C at sea level.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "The Moon is made of cheese.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "The Pacific is the deepest ocean.", + "confidence": "medium", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Mostly True", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "True (high) — Water boils at 100 C at sea level.\nFalse (high) — The Moon is made of cheese.\nMostly True (medium) — The Pacific is the deepest ocean.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Water boils at 100 C at sea level.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"The Moon is made of cheese.\",\n \"language\": \"en\",\n \"verdict\": \"False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"The Pacific is the deepest ocean.\",\n \"language\": \"en\",\n \"verdict\": \"Mostly True\",\n \"confidence\": \"medium\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/assess__suggest_rewrite.json b/tests/fixtures/parity/expected/assess__suggest_rewrite.json new file mode 100644 index 0000000..da850bb --- /dev/null +++ b/tests/fixtures/parity/expected/assess__suggest_rewrite.json @@ -0,0 +1,40 @@ +{ + "dump": { + "candidate_claims": [], + "claims": [ + { + "candidate_claims": [], + "claim": "Venus is the closest planet to the Sun.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": "Mercury, not Venus, is the closest planet to the Sun.", + "suggested_rewrite": "Mercury is the closest planet to the Sun.", + "verdict": "False", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Mercury is the closest planet to the Sun.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": "Mercury is the innermost planet.", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "error_code": "", + "more_claims": [] + }, + "render": "False (high) — Venus is the closest planet to the Sun.\n Mercury, not Venus, is the closest planet to the Sun.\nTrue (high) — Mercury is the closest planet to the Sun.\n Mercury is the innermost planet.\n", + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Venus is the closest planet to the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"Mercury, not Venus, is the closest planet to the Sun.\",\n \"dissent\": null,\n \"suggested_rewrite\": \"Mercury is the closest planet to the Sun.\",\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Mercury is the closest planet to the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"Mercury is the innermost planet.\",\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/citecheck__402_no_credits.json b/tests/fixtures/parity/expected/citecheck__402_no_credits.json new file mode 100644 index 0000000..9d5ec22 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__402_no_credits.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "No remaining credits for citation checks.", + "code": "no_credits", + "cost": 1, + "credit_balance": 100, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "No remaining credits for citation checks.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "No remaining credits for citation checks.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "No remaining credits for citation checks.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 100, + "request_id": "", + "requested": null, + "resets_at": "2026-10-01T09:14:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_empty_body.json b/tests/fixtures/parity/expected/citecheck__422_empty_body.json new file mode 100644 index 0000000..26fe6bc --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_empty_body.json @@ -0,0 +1,30 @@ +{ + "error": { + "cause": "payload: Value error, send exactly one of text and pairs", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload" + ], + "msg": "Value error, send exactly one of text and pairs" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload: Value error, send exactly one of text and pairs\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload: Value error, send exactly one of text and pairs", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload: Value error, send exactly one of text and pairs", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_invalid_doi.json b/tests/fixtures/parity/expected/citecheck__422_invalid_doi.json new file mode 100644 index 0000000..3e13201 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_invalid_doi.json @@ -0,0 +1,33 @@ +{ + "error": { + "cause": "payload.pairs.0.doi: Send the DOI alone, like 10.1038/nature12373.", + "code": "invalid_doi", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0, + "doi" + ], + "msg": "Send the DOI alone, like 10.1038/nature12373." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.pairs.0.doi: Send the DOI alone, like 10.1038/nature12373.\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0.doi: Send the DOI alone, like 10.1038/nature12373.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0.doi: Send the DOI alone, like 10.1038/nature12373.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_max_citations_over_20.json b/tests/fixtures/parity/expected/citecheck__422_max_citations_over_20.json new file mode 100644 index 0000000..aae4ebc --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_max_citations_over_20.json @@ -0,0 +1,31 @@ +{ + "error": { + "cause": "payload.max_citations: Input should be less than or equal to 20", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "max_citations" + ], + "msg": "Input should be less than or equal to 20" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.max_citations: Input should be less than or equal to 20\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.max_citations: Input should be less than or equal to 20", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.max_citations: Input should be less than or equal to 20", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_max_citations_with_pairs.json b/tests/fixtures/parity/expected/citecheck__422_max_citations_with_pairs.json new file mode 100644 index 0000000..f08b4c2 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_max_citations_with_pairs.json @@ -0,0 +1,30 @@ +{ + "error": { + "cause": "payload: Value error, max_citations goes with text: every pair is checked", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload" + ], + "msg": "Value error, max_citations goes with text: every pair is checked" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload: Value error, max_citations goes with text: every pair is checked\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload: Value error, max_citations goes with text: every pair is checked", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload: Value error, max_citations goes with text: every pair is checked", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_pair_bad_url_scheme.json b/tests/fixtures/parity/expected/citecheck__422_pair_bad_url_scheme.json new file mode 100644 index 0000000..76595fb --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_pair_bad_url_scheme.json @@ -0,0 +1,33 @@ +{ + "error": { + "cause": "payload.pairs.0.url: Value error, url: an http or https link", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0, + "url" + ], + "msg": "Value error, url: an http or https link" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.pairs.0.url: Value error, url: an http or https link\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0.url: Value error, url: an http or https link", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0.url: Value error, url: an http or https link", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_pair_no_source.json b/tests/fixtures/parity/expected/citecheck__422_pair_no_source.json new file mode 100644 index 0000000..f8ebec7 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_pair_no_source.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.pairs.0: Value error, send exactly one of url and doi", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0 + ], + "msg": "Value error, send exactly one of url and doi" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.pairs.0: Value error, send exactly one of url and doi\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0: Value error, send exactly one of url and doi", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0: Value error, send exactly one of url and doi", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_pair_url_and_doi.json b/tests/fixtures/parity/expected/citecheck__422_pair_url_and_doi.json new file mode 100644 index 0000000..f8ebec7 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_pair_url_and_doi.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.pairs.0: Value error, send exactly one of url and doi", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0 + ], + "msg": "Value error, send exactly one of url and doi" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.pairs.0: Value error, send exactly one of url and doi\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0: Value error, send exactly one of url and doi", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0: Value error, send exactly one of url and doi", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_pairs_empty.json b/tests/fixtures/parity/expected/citecheck__422_pairs_empty.json new file mode 100644 index 0000000..53538a0 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_pairs_empty.json @@ -0,0 +1,31 @@ +{ + "error": { + "cause": "payload.pairs: Value error, pairs: 1 to 20 items", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs" + ], + "msg": "Value error, pairs: 1 to 20 items" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.pairs: Value error, pairs: 1 to 20 items\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.pairs: Value error, pairs: 1 to 20 items", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.pairs: Value error, pairs: 1 to 20 items", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_pairs_over_20.json b/tests/fixtures/parity/expected/citecheck__422_pairs_over_20.json new file mode 100644 index 0000000..53538a0 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_pairs_over_20.json @@ -0,0 +1,31 @@ +{ + "error": { + "cause": "payload.pairs: Value error, pairs: 1 to 20 items", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs" + ], + "msg": "Value error, pairs: 1 to 20 items" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.pairs: Value error, pairs: 1 to 20 items\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.pairs: Value error, pairs: 1 to 20 items", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.pairs: Value error, pairs: 1 to 20 items", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_quote_not_in_statement.json b/tests/fixtures/parity/expected/citecheck__422_quote_not_in_statement.json new file mode 100644 index 0000000..96e097c --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_quote_not_in_statement.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.pairs.0: Each quote must be words of its statement.", + "code": "quote_not_in_statement", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0 + ], + "msg": "Each quote must be words of its statement." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.pairs.0: Each quote must be words of its statement.\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0: Each quote must be words of its statement.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0: Each quote must be words of its statement.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_text_and_pairs.json b/tests/fixtures/parity/expected/citecheck__422_text_and_pairs.json new file mode 100644 index 0000000..26fe6bc --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_text_and_pairs.json @@ -0,0 +1,30 @@ +{ + "error": { + "cause": "payload: Value error, send exactly one of text and pairs", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload" + ], + "msg": "Value error, send exactly one of text and pairs" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload: Value error, send exactly one of text and pairs\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload: Value error, send exactly one of text and pairs", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload: Value error, send exactly one of text and pairs", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_unknown_field.json b/tests/fixtures/parity/expected/citecheck__422_unknown_field.json new file mode 100644 index 0000000..bafff34 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_unknown_field.json @@ -0,0 +1,33 @@ +{ + "error": { + "cause": "payload.pairs.0.extra: Extra inputs are not permitted", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0, + "extra" + ], + "msg": "Extra inputs are not permitted" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.pairs.0.extra: Extra inputs are not permitted\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0.extra: Extra inputs are not permitted", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.pairs.0.extra: Extra inputs are not permitted", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__422_url_input.json b/tests/fixtures/parity/expected/citecheck__422_url_input.json new file mode 100644 index 0000000..d5d08dc --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_url_input.json @@ -0,0 +1,30 @@ +{ + "error": { + "cause": "Send the page's text, with its links, to check the sources it cites.", + "code": "url_input", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "text" + ], + "msg": "Send the page's text, with its links, to check the sources it cites." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Send the page's text, with its links, to check the sources it cites.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Send the page's text, with its links, to check the sources it cites.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Send the page's text, with its links, to check the sources it cites.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__429_citecheck_in_flight.json b/tests/fixtures/parity/expected/citecheck__429_citecheck_in_flight.json new file mode 100644 index 0000000..45b31c1 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__429_citecheck_in_flight.json @@ -0,0 +1,25 @@ +{ + "error": { + "cause": "This account already has 3 citation checks running. Wait for one to finish.", + "code": "citecheck_in_flight", + "doc_url": "https://lenz.io/docs/rate-limits", + "fix": "Wait Retry-After seconds and retry.", + "friendly_text": "This account already has 3 citation checks running. Wait for one to finish.\n Fix: Wait Retry-After seconds and retry.", + "limit": null, + "message": "This account already has 3 citation checks running. Wait for one to finish.", + "payload_json": { + "error": { + "code": "rate_limited", + "fix": "Wait Retry-After seconds and retry.", + "message": "This account already has 3 citation checks running. Wait for one to finish.", + "status": 429 + } + }, + "request_id": "", + "reset_in_seconds": null, + "retry_after": 60, + "status_code": 429, + "type": "LenzRateLimitError", + "upgrade_url": "" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__503_capacity.json b/tests/fixtures/parity/expected/citecheck__503_capacity.json new file mode 100644 index 0000000..5384727 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__503_capacity.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 90, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__503_citations_unavailable.json b/tests/fixtures/parity/expected/citecheck__503_citations_unavailable.json new file mode 100644 index 0000000..d3cc317 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__503_citations_unavailable.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Citation checking is switched off right now. Retry later; nothing was charged.", + "code": "citations_unavailable", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Citation checking is switched off right now. Retry later; nothing was charged.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Citation checking is switched off right now. Retry later; nothing was charged.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Citation checking is switched off right now. Retry later; nothing was charged.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 300, + "status_code": 503, + "type": "LenzAPIError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__get_404_not_found.json b/tests/fixtures/parity/expected/citecheck__get_404_not_found.json new file mode 100644 index 0000000..b1353bd --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_404_not_found.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Citation check not found.", + "code": "not_found", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Citation check not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Citation check not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Citation check not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__get_404_review_id.json b/tests/fixtures/parity/expected/citecheck__get_404_review_id.json new file mode 100644 index 0000000..b1353bd --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_404_review_id.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Citation check not found.", + "code": "not_found", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Citation check not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Citation check not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Citation check not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__get_410_purged.json b/tests/fixtures/parity/expected/citecheck__get_410_purged.json new file mode 100644 index 0000000..6cf59a9 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_410_purged.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "This check is no longer available: its account removes content after a set period.", + "code": "purged", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Its account's retention period removed it. A certificate issued for it is still available.", + "friendly_text": "This check is no longer available: its account removes content after a set period.\n Fix: Its account's retention period removed it. A certificate issued for it is still available.", + "message": "This check is no longer available: its account removes content after a set period.", + "payload_json": { + "error": { + "code": "gone", + "fix": "Its account's retention period removed it. A certificate issued for it is still available.", + "message": "This check is no longer available: its account removes content after a set period.", + "status": 410 + } + }, + "purged_at": "2026-10-01T09:07:00.123456Z", + "request_id": "", + "status_code": 410, + "type": "LenzGoneError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__get_checking.json b/tests/fixtures/parity/expected/citecheck__get_checking.json new file mode 100644 index 0000000..c5352dd --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_checking.json @@ -0,0 +1,100 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "pending", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": null, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "pending", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": null, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": null, + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": 10, + "status": "checking", + "summary": { + "citation_checks": { + "checked": 0, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "exit_code": 2, + "render": "Citation check 8eb49302: checking — 0 credits charged\n\n2 sources cited in your draft\nLenz checks each one: does the source say what your draft says it does.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_clean.json b/tests/fixtures/parity/expected/citecheck__get_completed_clean.json new file mode 100644 index 0000000..0b78c9e --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_completed_clean.json @@ -0,0 +1,108 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "clean", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "exit_code": 0, + "render": "Citation check 8eb49302: clean — 2 credits charged\n\n2 sources cited in your draft\n2 checked.\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_doi_pair.json b/tests/fixtures/parity/expected/citecheck__get_completed_doi_pair.json new file mode 100644 index 0000000..1857179 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_completed_doi_pair.json @@ -0,0 +1,73 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at None", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": null, + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://doi.org/10.1038/nature12373", + "doi": "10.1038/nature12373", + "index": 0, + "position": null, + "quotes": [], + "reference": "10.1038/nature12373", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Diamond sensors measure heat in cells." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "clean", + "policy": { + "max_citations": 1 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 1, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 1, + "citation_limit_reached": false, + "citations_found": 1, + "citations_selected": 1 + } + }, + "exit_code": 0, + "render": "Citation check 8eb49302: clean — 1 credit charged\n\n1 source cited in your draft\n1 checked.\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_incomplete.json b/tests/fixtures/parity/expected/citecheck__get_completed_incomplete.json new file mode 100644 index 0000000..267612f --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_completed_incomplete.json @@ -0,0 +1,124 @@ +{ + "dump": { + "citation_failures": [ + { + "citation_index": 1, + "cited_url": "https://example.org/statement", + "doi": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#internal", + "failure_class": "internal", + "failure_reason": "internal", + "hint": "The check failed on our side. Try again later.", + "retryable": false + }, + "reference": "https://example.org/statement" + } + ], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#internal", + "failure_class": "internal", + "failure_reason": "internal", + "hint": "The check failed on our side. Try again later.", + "retryable": false + }, + "hint": "The check failed on our side. Try again later.", + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "failed", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": null, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "incomplete", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 1, + "failed": 1, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "exit_code": 2, + "render": "Citation check 8eb49302: incomplete — 1 credit charged\n\n2 sources cited in your draft\n1 checked. 1 could not be checked.\n\n[source 2/2] Could not be checked this time.\n https://example.org/statement\n The check failed on our side. Try again later.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_issues_found.json b/tests/fixtures/parity/expected/citecheck__get_completed_issues_found.json new file mode 100644 index 0000000..0bee066 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_completed_issues_found.json @@ -0,0 +1,138 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": null, + "finding": "contradicted", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "rationale": "The page states it.", + "reference": "a report from the ministry", + "snippet": "The source says so.", + "source": "support", + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + } + ], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "contradicted", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "contradicted", + "is_issue": true, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "issues_found", + "policy": { + "max_citations": 20 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 1, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "exit_code": 1, + "render": "Citation check 8eb49302: issues found — 2 credits charged\n\n2 sources cited in your draft\n2 checked, 1 with a problem.\n\n[source 1/2] Contradicted\n Unemployment fell to 4.1% in 2024, according to a report from the ministry.\n https://example.gov/report-2024\n The source says:\n “The source says so.”\n Reviewer's note: The page states it.\n\nA reviewer's note is reasoning, not a checked source; the quoted passage is from the page.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_partly_supported.json b/tests/fixtures/parity/expected/citecheck__get_completed_partly_supported.json new file mode 100644 index 0000000..3d302ef --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_completed_partly_supported.json @@ -0,0 +1,108 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "partly_supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": { + "finding": "partly_supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "clean", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "exit_code": 0, + "render": "Citation check 8eb49302: clean — 2 credits charged\n\n2 sources cited in your draft\n2 checked.\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_unchecked.json b/tests/fixtures/parity/expected/citecheck__get_completed_unchecked.json new file mode 100644 index 0000000..4e9a931 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_completed_unchecked.json @@ -0,0 +1,108 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": null, + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "unchecked", + "unchecked_reason": "no_text" + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": { + "finding": "unchecked", + "is_issue": false, + "source": null + }, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": null, + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "unchecked", + "unchecked_reason": "no_text" + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": { + "finding": "unchecked", + "is_issue": false, + "source": null + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "unchecked", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 0, + "failed": 0, + "unchecked": 2 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "exit_code": 2, + "render": "Citation check 8eb49302: unchecked — 0 credits charged\n\n2 sources cited in your draft\n2 could not be checked.\n\nCheck these by hand (Lenz could not check them)\n[source 1/2] The page gave no text to read.\n https://example.gov/report-2024\n[source 2/2] The page gave no text to read.\n https://example.org/statement\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_failed_no_citations.json b/tests/fixtures/parity/expected/citecheck__get_failed_no_citations.json new file mode 100644 index 0000000..2fcc755 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_failed_no_citations.json @@ -0,0 +1,39 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "no_citations", + "hint": "The text has no citation to check: no link, DOI or numbered reference with one.", + "retryable": false + }, + "language": "en", + "more_citations": null, + "outcome": "unchecked", + "policy": { + "max_citations": 20 + }, + "poll_after_seconds": null, + "status": "failed", + "summary": { + "citation_checks": null, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null + } + }, + "exit_code": 2, + "render": "Citation check 8eb49302: unchecked — 0 credits charged\nFailed: The text has no citation to check: no link, DOI or numbered reference with one.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_failed_upstream_unavailable.json b/tests/fixtures/parity/expected/citecheck__get_failed_upstream_unavailable.json new file mode 100644 index 0000000..81d92d8 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_failed_upstream_unavailable.json @@ -0,0 +1,145 @@ +{ + "dump": { + "citation_failures": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "Lenz could not reach this source just now. Try again later.", + "retryable": true + }, + "reference": "a report from the ministry" + }, + { + "citation_index": 1, + "cited_url": "https://example.org/statement", + "doi": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "Lenz could not reach this source just now. Try again later.", + "retryable": true + }, + "reference": "a statement" + } + ], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "Lenz could not reach this source just now. Try again later.", + "retryable": true + }, + "hint": "Lenz could not reach this source just now. Try again later.", + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "failed", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "a report from the ministry", + "result": null, + "statement": null + }, + { + "check": { + "doi_registered": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "Lenz could not reach this source just now. Try again later.", + "retryable": true + }, + "hint": "Lenz could not reach this source just now. Try again later.", + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "failed", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "a statement", + "result": null, + "statement": null + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": null, + "retryable": true + }, + "language": "en", + "more_citations": [], + "outcome": "unchecked", + "policy": { + "max_citations": 20 + }, + "poll_after_seconds": null, + "status": "failed", + "summary": { + "citation_checks": { + "checked": 0, + "failed": 2, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "exit_code": 2, + "render": "Citation check 8eb49302: unchecked — 0 credits charged\nFailed: upstream_unavailable\n\n2 sources cited in your draft\n2 could not be checked.\n\n[source 1/2] Could not be checked this time.\n https://example.gov/report-2024\n Lenz could not reach this source just now. Try again later.\n\n[source 2/2] Could not be checked this time.\n https://example.org/statement\n Lenz could not reach this source just now. Try again later.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_queued.json b/tests/fixtures/parity/expected/citecheck__get_queued.json new file mode 100644 index 0000000..402fbe9 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_queued.json @@ -0,0 +1,69 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "pending", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": null, + "statement": "Unemployment fell to 4.1% in 2024." + } + ], + "citecheck_id": "8eb49302", + "completed_at": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": null, + "policy": { + "max_citations": 1 + }, + "poll_after_seconds": 10, + "status": "queued", + "summary": { + "citation_checks": { + "checked": 0, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 1, + "citation_limit_reached": false, + "citations_found": 1, + "citations_selected": 1 + } + }, + "exit_code": 2, + "render": "Citation check 8eb49302: queued — 0 credits charged\n\n1 source cited in your draft\nLenz checks each one: does the source say what your draft says it does.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_text_limit_exactly_at_limit.json b/tests/fixtures/parity/expected/citecheck__get_text_limit_exactly_at_limit.json new file mode 100644 index 0000000..174ac25 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_text_limit_exactly_at_limit.json @@ -0,0 +1,116 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "clean", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "exit_code": 0, + "render": "Citation check 8eb49302: clean — 2 credits charged\n\n2 sources cited in your draft\n2 checked.\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__get_text_limit_reached.json b/tests/fixtures/parity/expected/citecheck__get_text_limit_reached.json new file mode 100644 index 0000000..b97967a --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__get_text_limit_reached.json @@ -0,0 +1,90 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "language": "en", + "more_citations": [ + { + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "reference": "a statement", + "sentence": "The agency said so in a statement." + } + ], + "outcome": "clean", + "policy": { + "max_citations": 1 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 1, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 1, + "citation_limit_reached": true, + "citations_found": 2, + "citations_selected": 1 + } + }, + "exit_code": 0, + "render": "Citation check 8eb49302: clean — 1 credit charged\n\n2 sources cited in your draft\n1 checked.\n1 more was not checked: one check covers 1.\n\nNo issues.\n\n1 more citation was found but not checked.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__idempotency_body_mismatch_422.json b/tests/fixtures/parity/expected/citecheck__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..5de20e3 --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__idempotency_body_mismatch_422.json @@ -0,0 +1,29 @@ +{ + "error": { + "cause": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "header" + ], + "msg": "Idempotency-Key reused with a different request body." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Idempotency-Key reused with a different request body.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__idempotency_conflict_409.json b/tests/fixtures/parity/expected/citecheck__idempotency_conflict_409.json new file mode 100644 index 0000000..f674e5f --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__idempotency_conflict_409.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "A check with this Idempotency-Key is still being created. Retry shortly.", + "code": "idempotency_conflict", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "A check with this Idempotency-Key is still being created. Retry shortly.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "A check with this Idempotency-Key is still being created. Retry shortly.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "A check with this Idempotency-Key is still being created. Retry shortly.", + "status": 409 + } + }, + "request_id": "", + "status_code": 409, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__idempotent_replay_202.json b/tests/fixtures/parity/expected/citecheck__idempotent_replay_202.json new file mode 100644 index 0000000..6ebcb9b --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__idempotent_replay_202.json @@ -0,0 +1,7 @@ +{ + "dump": { + "citecheck_id": "8eb49302", + "status": "queued" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__receipt_202.json b/tests/fixtures/parity/expected/citecheck__receipt_202.json new file mode 100644 index 0000000..6ebcb9b --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__receipt_202.json @@ -0,0 +1,7 @@ +{ + "dump": { + "citecheck_id": "8eb49302", + "status": "queued" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/citecheck__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/expected/citecheck__receipt_202_empty_webhook_url.json new file mode 100644 index 0000000..6ebcb9b --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__receipt_202_empty_webhook_url.json @@ -0,0 +1,7 @@ +{ + "dump": { + "citecheck_id": "8eb49302", + "status": "queued" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/errors__ask_bad_language.json b/tests/fixtures/parity/expected/errors__ask_bad_language.json new file mode 100644 index 0000000..81b1bdf --- /dev/null +++ b/tests/fixtures/parity/expected/errors__ask_bad_language.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Unsupported language 'xx-nope'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Unsupported language 'xx-nope'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Unsupported language 'xx-nope'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Unsupported language 'xx-nope'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/errors__ask_empty_message.json b/tests/fixtures/parity/expected/errors__ask_empty_message.json new file mode 100644 index 0000000..817db2b --- /dev/null +++ b/tests/fixtures/parity/expected/errors__ask_empty_message.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Message cannot be empty.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Message cannot be empty.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Message cannot be empty.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Message cannot be empty.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/errors__ask_failed.json b/tests/fixtures/parity/expected/errors__ask_failed.json new file mode 100644 index 0000000..4aa0601 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__ask_failed.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "The chat model could not answer this question.", + "code": "ask_failed", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "The chat model could not answer this question.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "The chat model could not answer this question.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "The chat model could not answer this question.", + "status": 502 + } + }, + "request_id": "", + "retry_after": null, + "status_code": 502, + "type": "LenzAPIError" + } +} diff --git a/tests/fixtures/parity/expected/errors__ask_idempotency_key_reused.json b/tests/fixtures/parity/expected/errors__ask_idempotency_key_reused.json new file mode 100644 index 0000000..989af48 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__ask_idempotency_key_reused.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Idempotency-Key reused with a different request body.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Idempotency-Key reused with a different request body.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/errors__ask_message_too_long.json b/tests/fixtures/parity/expected/errors__ask_message_too_long.json new file mode 100644 index 0000000..8345a29 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__ask_message_too_long.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Message too long (max 500 characters).", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Message too long (max 500 characters).\n Fix: Check the request body against the OpenAPI spec.", + "message": "Message too long (max 500 characters).", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Message too long (max 500 characters).", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/errors__ask_not_completed.json b/tests/fixtures/parity/expected/errors__ask_not_completed.json new file mode 100644 index 0000000..cfdc7c3 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__ask_not_completed.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Ask is only available for completed verifications.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Ask is only available for completed verifications.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Ask is only available for completed verifications.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Ask is only available for completed verifications.", + "status": 400 + } + }, + "request_id": "", + "status_code": 400, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__ask_reset_not_found.json b/tests/fixtures/parity/expected/errors__ask_reset_not_found.json new file mode 100644 index 0000000..956264c --- /dev/null +++ b/tests/fixtures/parity/expected/errors__ask_reset_not_found.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Verification not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Verification not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Verification not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Verification not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__ask_send_not_found.json b/tests/fixtures/parity/expected/errors__ask_send_not_found.json new file mode 100644 index 0000000..956264c --- /dev/null +++ b/tests/fixtures/parity/expected/errors__ask_send_not_found.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Verification not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Verification not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Verification not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Verification not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_bad_key.json b/tests/fixtures/parity/expected/errors__auth_bad_key.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_bad_key.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_basic_scheme.json b/tests/fixtures/parity/expected/errors__auth_basic_scheme.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_basic_scheme.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_insufficient_scope.json b/tests/fixtures/parity/expected/errors__auth_insufficient_scope.json new file mode 100644 index 0000000..567f3ae --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_insufficient_scope.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "The access token does not allow this call.", + "code": "insufficient_scope", + "doc_url": "https://lenz.io/docs/auth", + "fix": "This key doesn't have access to that resource.", + "friendly_text": "The access token does not allow this call.\n Fix: This key doesn't have access to that resource.", + "message": "The access token does not allow this call.", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "This key doesn't have access to that resource.", + "message": "The access token does not allow this call.", + "status": 403 + } + }, + "request_id": "", + "status_code": 403, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_missing_bearer.json b/tests/fixtures/parity/expected/errors__auth_missing_bearer.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_missing_bearer.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_missing_bearer_post.json b/tests/fixtures/parity/expected/errors__auth_missing_bearer_post.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_missing_bearer_post.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_private_claim_ask_history.json b/tests/fixtures/parity/expected/errors__auth_private_claim_ask_history.json new file mode 100644 index 0000000..a29a3fb --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_private_claim_ask_history.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "This report is private.", + "code": "private_claim", + "doc_url": "https://lenz.io/docs/auth", + "fix": "This key doesn't have access to that resource.", + "friendly_text": "This report is private.\n Fix: This key doesn't have access to that resource.", + "message": "This report is private.", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "This key doesn't have access to that resource.", + "message": "This report is private.", + "status": 403 + } + }, + "request_id": "", + "status_code": 403, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_private_claim_ask_send.json b/tests/fixtures/parity/expected/errors__auth_private_claim_ask_send.json new file mode 100644 index 0000000..a29a3fb --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_private_claim_ask_send.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "This report is private.", + "code": "private_claim", + "doc_url": "https://lenz.io/docs/auth", + "fix": "This key doesn't have access to that resource.", + "friendly_text": "This report is private.\n Fix: This key doesn't have access to that resource.", + "message": "This report is private.", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "This key doesn't have access to that resource.", + "message": "This report is private.", + "status": 403 + } + }, + "request_id": "", + "status_code": 403, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_unrecognised_prefix.json b/tests/fixtures/parity/expected/errors__auth_unrecognised_prefix.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_unrecognised_prefix.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__http_error_library_bad_curated.json b/tests/fixtures/parity/expected/errors__http_error_library_bad_curated.json new file mode 100644 index 0000000..9eb06ac --- /dev/null +++ b/tests/fixtures/parity/expected/errors__http_error_library_bad_curated.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Invalid curated list(s). Allowed: trivia", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Invalid curated list(s). Allowed: trivia\n Fix: Check the request body against the OpenAPI spec.", + "message": "Invalid curated list(s). Allowed: trivia", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Invalid curated list(s). Allowed: trivia", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/errors__http_error_library_bad_verdict.json b/tests/fixtures/parity/expected/errors__http_error_library_bad_verdict.json new file mode 100644 index 0000000..2dce420 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__http_error_library_bad_verdict.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Invalid verdict label(s). Allowed: False, Mostly False, Mixed, Mostly True, True", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Invalid verdict label(s). Allowed: False, Mostly False, Mixed, Mostly True, True\n Fix: Check the request body against the OpenAPI spec.", + "message": "Invalid verdict label(s). Allowed: False, Mostly False, Mixed, Mostly True, True", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Invalid verdict label(s). Allowed: False, Mostly False, Mixed, Mostly True, True", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/errors__not_found_ask.json b/tests/fixtures/parity/expected/errors__not_found_ask.json new file mode 100644 index 0000000..956264c --- /dev/null +++ b/tests/fixtures/parity/expected/errors__not_found_ask.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Verification not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Verification not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Verification not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Verification not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__not_found_route.json b/tests/fixtures/parity/expected/errors__not_found_route.json new file mode 100644 index 0000000..8c9406d --- /dev/null +++ b/tests/fixtures/parity/expected/errors__not_found_route.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 404", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 404\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 404", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 404", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__not_found_verification.json b/tests/fixtures/parity/expected/errors__not_found_verification.json new file mode 100644 index 0000000..41573fe --- /dev/null +++ b/tests/fixtures/parity/expected/errors__not_found_verification.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__not_found_verify_status.json b/tests/fixtures/parity/expected/errors__not_found_verify_status.json new file mode 100644 index 0000000..68a468c --- /dev/null +++ b/tests/fixtures/parity/expected/errors__not_found_verify_status.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Task not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Task not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Task not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Task not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__payment_required_ask.json b/tests/fixtures/parity/expected/errors__payment_required_ask.json new file mode 100644 index 0000000..e519757 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__payment_required_ask.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "No remaining ask credits.", + "code": "no_credits", + "cost": 1, + "credit_balance": 0, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "No remaining ask credits.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "No remaining ask credits.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "No remaining ask credits.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 0, + "request_id": "", + "requested": null, + "resets_at": "2026-10-01T09:14:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/errors__payment_required_assess.json b/tests/fixtures/parity/expected/errors__payment_required_assess.json new file mode 100644 index 0000000..732bc39 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__payment_required_assess.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "No remaining /assess units.", + "code": "no_credits", + "cost": 1, + "credit_balance": 0, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "No remaining /assess units.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "No remaining /assess units.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "No remaining /assess units.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 0, + "request_id": "", + "requested": null, + "resets_at": "2026-10-01T09:14:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/errors__payment_required_verify.json b/tests/fixtures/parity/expected/errors__payment_required_verify.json new file mode 100644 index 0000000..f3a12a3 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__payment_required_verify.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "No remaining claim checks.", + "code": "no_credits", + "cost": 10, + "credit_balance": 0, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "No remaining claim checks.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "No remaining claim checks.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "No remaining claim checks.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 0, + "request_id": "", + "requested": null, + "resets_at": "2026-10-01T09:14:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/errors__payment_required_verify_batch_short.json b/tests/fixtures/parity/expected/errors__payment_required_verify_batch_short.json new file mode 100644 index 0000000..4506242 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__payment_required_verify_batch_short.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "Insufficient credits for batch.", + "code": "no_credits", + "cost": 50, + "credit_balance": 30, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "Insufficient credits for batch.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "Insufficient credits for batch.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "Insufficient credits for batch.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 3, + "request_id": "", + "requested": 5, + "resets_at": "2026-10-01T09:14:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/errors__rate_limited_extract.json b/tests/fixtures/parity/expected/errors__rate_limited_extract.json new file mode 100644 index 0000000..336a59b --- /dev/null +++ b/tests/fixtures/parity/expected/errors__rate_limited_extract.json @@ -0,0 +1,25 @@ +{ + "error": { + "cause": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", + "code": "extract_daily_limit", + "doc_url": "https://lenz.io/docs/rate-limits", + "fix": "Wait Retry-After seconds and retry.", + "friendly_text": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.\n Fix: Wait Retry-After seconds and retry.", + "limit": 1000, + "message": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", + "payload_json": { + "error": { + "code": "rate_limited", + "fix": "Wait Retry-After seconds and retry.", + "message": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", + "status": 429 + } + }, + "request_id": "", + "reset_in_seconds": 900, + "retry_after": 900, + "status_code": 429, + "type": "LenzRateLimitError", + "upgrade_url": "https://lenz.io/plans" + } +} diff --git a/tests/fixtures/parity/expected/errors__service_unavailable_ask.json b/tests/fixtures/parity/expected/errors__service_unavailable_ask.json new file mode 100644 index 0000000..c9e8778 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__service_unavailable_ask.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "The chat model is unavailable right now. Retry shortly.", + "code": "upstream_unavailable", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "The chat model is unavailable right now. Retry shortly.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "The chat model is unavailable right now. Retry shortly.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "The chat model is unavailable right now. Retry shortly.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 90, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/errors__service_unavailable_capacity.json b/tests/fixtures/parity/expected/errors__service_unavailable_capacity.json new file mode 100644 index 0000000..b628bec --- /dev/null +++ b/tests/fixtures/parity/expected/errors__service_unavailable_capacity.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 60, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/errors__validation_malformed_json.json b/tests/fixtures/parity/expected/errors__validation_malformed_json.json new file mode 100644 index 0000000..4321bb7 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__validation_malformed_json.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Cannot parse request body (Expecting property name enclosed in double quotes: line 1 column 2 (char 1))", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Cannot parse request body (Expecting property name enclosed in double quotes: line 1 column 2 (char 1))\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Cannot parse request body (Expecting property name enclosed in double quotes: line 1 column 2 (char 1))", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Cannot parse request body (Expecting property name enclosed in double quotes: line 1 column 2 (char 1))", + "status": 400 + } + }, + "request_id": "", + "status_code": 400, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__validation_missing_field_hint.json b/tests/fixtures/parity/expected/errors__validation_missing_field_hint.json new file mode 100644 index 0000000..6760d1a --- /dev/null +++ b/tests/fixtures/parity/expected/errors__validation_missing_field_hint.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/errors__validation_unknown_field_only.json b/tests/fixtures/parity/expected/errors__validation_unknown_field_only.json new file mode 100644 index 0000000..6760d1a --- /dev/null +++ b/tests/fixtures/parity/expected/errors__validation_unknown_field_only.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/errors__validation_unknown_field_wrong_type.json b/tests/fixtures/parity/expected/errors__validation_unknown_field_wrong_type.json new file mode 100644 index 0000000..7713b4c --- /dev/null +++ b/tests/fixtures/parity/expected/errors__validation_unknown_field_wrong_type.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "[{'type': 'list_type', 'loc': ['body', 'payload', 'claims'], 'msg': 'Input should be a valid list'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "claims" + ], + "msg": "Input should be a valid list", + "type": "list_type" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'list_type', 'loc': ['body', 'payload', 'claims'], 'msg': 'Input should be a valid list'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'list_type', 'loc': ['body', 'payload', 'claims'], 'msg': 'Input should be a valid list'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'list_type', 'loc': ['body', 'payload', 'claims'], 'msg': 'Input should be a valid list'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/errors__validation_wrong_type.json b/tests/fixtures/parity/expected/errors__validation_wrong_type.json new file mode 100644 index 0000000..bf16952 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__validation_wrong_type.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "[{'type': 'string_type', 'loc': ['body', 'payload', 'text'], 'msg': 'Input should be a valid string'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Input should be a valid string", + "type": "string_type" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'string_type', 'loc': ['body', 'payload', 'text'], 'msg': 'Input should be a valid string'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'string_type', 'loc': ['body', 'payload', 'text'], 'msg': 'Input should be a valid string'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'string_type', 'loc': ['body', 'payload', 'text'], 'msg': 'Input should be a valid string'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/extract__401_no_key.json b/tests/fixtures/parity/expected/extract__401_no_key.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/extract__401_no_key.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/extract__422_blank_text.json b/tests/fixtures/parity/expected/extract__422_blank_text.json new file mode 100644 index 0000000..872ff11 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__422_blank_text.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Text is required.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Text is required.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Text is required.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Text is required.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/extract__422_focus_too_long.json b/tests/fixtures/parity/expected/extract__422_focus_too_long.json new file mode 100644 index 0000000..e658cd0 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__422_focus_too_long.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "focus must be at most 300 characters of plain text.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "focus must be at most 300 characters of plain text.\n Fix: Check the request body against the OpenAPI spec.", + "message": "focus must be at most 300 characters of plain text.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "focus must be at most 300 characters of plain text.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/extract__422_missing_text.json b/tests/fixtures/parity/expected/extract__422_missing_text.json new file mode 100644 index 0000000..6760d1a --- /dev/null +++ b/tests/fixtures/parity/expected/extract__422_missing_text.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/extract__429_daily_limit.json b/tests/fixtures/parity/expected/extract__429_daily_limit.json new file mode 100644 index 0000000..fe317f9 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__429_daily_limit.json @@ -0,0 +1,25 @@ +{ + "error": { + "cause": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", + "code": "extract_daily_limit", + "doc_url": "https://lenz.io/docs/rate-limits", + "fix": "Wait Retry-After seconds and retry.", + "friendly_text": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.\n Fix: Wait Retry-After seconds and retry.", + "limit": 1000, + "message": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", + "payload_json": { + "error": { + "code": "rate_limited", + "fix": "Wait Retry-After seconds and retry.", + "message": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", + "status": 429 + } + }, + "request_id": "", + "reset_in_seconds": 3600, + "retry_after": 3600, + "status_code": 429, + "type": "LenzRateLimitError", + "upgrade_url": "https://lenz.io/plans" + } +} diff --git a/tests/fixtures/parity/expected/extract__502_extraction_failed.json b/tests/fixtures/parity/expected/extract__502_extraction_failed.json new file mode 100644 index 0000000..7ce9984 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__502_extraction_failed.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Extraction failed", + "code": "extraction_failed", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Extraction failed\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Extraction failed", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Extraction failed", + "status": 502 + } + }, + "request_id": "", + "retry_after": null, + "status_code": 502, + "type": "LenzAPIError" + } +} diff --git a/tests/fixtures/parity/expected/extract__503_upstream_unavailable.json b/tests/fixtures/parity/expected/extract__503_upstream_unavailable.json new file mode 100644 index 0000000..7553c4c --- /dev/null +++ b/tests/fixtures/parity/expected/extract__503_upstream_unavailable.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Our model providers are temporarily unavailable. Please retry shortly.", + "code": "upstream_unavailable", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Our model providers are temporarily unavailable. Please retry shortly.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Our model providers are temporarily unavailable. Please retry shortly.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Our model providers are temporarily unavailable. Please retry shortly.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 90, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/extract__focus_ready.json b/tests/fixtures/parity/expected/extract__focus_ready.json new file mode 100644 index 0000000..0b529b1 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__focus_ready.json @@ -0,0 +1,24 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Beta fell 3% last year.", + "domain": "Economics", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, + "render": "Claim: Beta fell 3% last year.\n\nVerify it: lenz verify \"Beta fell 3% last year.\"\n", + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Beta fell 3% last year.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__idempotency_body_mismatch_422.json b/tests/fixtures/parity/expected/extract__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..989af48 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__idempotency_body_mismatch_422.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Idempotency-Key reused with a different request body.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Idempotency-Key reused with a different request body.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/extract__idempotency_replay.json b/tests/fixtures/parity/expected/extract__idempotency_replay.json new file mode 100644 index 0000000..df61eab --- /dev/null +++ b/tests/fixtures/parity/expected/extract__idempotency_replay.json @@ -0,0 +1,27 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, + "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n 2. Beta fell 3% last year.\n", + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__locate_all_dropped.json b/tests/fixtures/parity/expected/extract__locate_all_dropped.json new file mode 100644 index 0000000..c015827 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__locate_all_dropped.json @@ -0,0 +1,24 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "", + "domain": "", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": [], + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "not_a_claim" + }, + "render": "No verifiable claim found in that text.\n", + "render_json": "{\n \"status\": \"not_a_claim\",\n \"claim\": \"\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": []\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__locate_failed.json b/tests/fixtures/parity/expected/extract__locate_failed.json new file mode 100644 index 0000000..df61eab --- /dev/null +++ b/tests/fixtures/parity/expected/extract__locate_failed.json @@ -0,0 +1,27 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, + "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n 2. Beta fell 3% last year.\n", + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__locate_leading_whitespace.json b/tests/fixtures/parity/expected/extract__locate_leading_whitespace.json new file mode 100644 index 0000000..a007c40 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__locate_leading_whitespace.json @@ -0,0 +1,35 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "end": 25, + "start": 3, + "text": "Alpha rose 5% in 2024." + } + ] + } + ], + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, + "render": "Claim: Alpha rose 5% in 2024.\n at 3-25: \"Alpha rose 5% in 2024.\"\n\nVerify it: lenz verify \"Alpha rose 5% in 2024.\"\n", + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": 3,\n \"end\": 25,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n }\n ]\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__locate_some_dropped.json b/tests/fixtures/parity/expected/extract__locate_some_dropped.json new file mode 100644 index 0000000..80d25e1 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__locate_some_dropped.json @@ -0,0 +1,48 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "end": 22, + "start": 0, + "text": "Alpha rose 5% in 2024." + } + ] + }, + { + "claim": "Beta fell 3% last year.", + "positions": [ + { + "end": 46, + "start": 23, + "text": "Beta fell 3% last year." + } + ] + } + ], + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, + "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n at 0-22: \"Alpha rose 5% in 2024.\"\n 2. Beta fell 3% last year.\n at 23-46: \"Beta fell 3% last year.\"\n", + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": 0,\n \"end\": 22,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n },\n {\n \"claim\": \"Beta fell 3% last year.\",\n \"positions\": [\n {\n \"start\": 23,\n \"end\": 46,\n \"text\": \"Beta fell 3% last year.\"\n }\n ]\n }\n ]\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__locate_true.json b/tests/fixtures/parity/expected/extract__locate_true.json new file mode 100644 index 0000000..80d25e1 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__locate_true.json @@ -0,0 +1,48 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "end": 22, + "start": 0, + "text": "Alpha rose 5% in 2024." + } + ] + }, + { + "claim": "Beta fell 3% last year.", + "positions": [ + { + "end": 46, + "start": 23, + "text": "Beta fell 3% last year." + } + ] + } + ], + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, + "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n at 0-22: \"Alpha rose 5% in 2024.\"\n 2. Beta fell 3% last year.\n at 23-46: \"Beta fell 3% last year.\"\n", + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": 0,\n \"end\": 22,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n },\n {\n \"claim\": \"Beta fell 3% last year.\",\n \"positions\": [\n {\n \"start\": 23,\n \"end\": 46,\n \"text\": \"Beta fell 3% last year.\"\n }\n ]\n }\n ]\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__no_match_with_focus.json b/tests/fixtures/parity/expected/extract__no_match_with_focus.json new file mode 100644 index 0000000..8097b22 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__no_match_with_focus.json @@ -0,0 +1,15 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "", + "domain": "", + "identified_claims": [], + "key_entities": [], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "", + "status": "no_match" + }, + "render": "No claims matched the focus.\n", + "render_json": "{\n \"status\": \"no_match\",\n \"claim\": \"\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"\",\n \"key_entities\": [],\n \"presumed_intent\": \"\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__not_a_claim.json b/tests/fixtures/parity/expected/extract__not_a_claim.json new file mode 100644 index 0000000..1e7d7fe --- /dev/null +++ b/tests/fixtures/parity/expected/extract__not_a_claim.json @@ -0,0 +1,15 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "", + "domain": "", + "identified_claims": [], + "key_entities": [], + "locations": null, + "original_input": "What a lovely day.", + "presumed_intent": "", + "status": "not_a_claim" + }, + "render": "No verifiable claim found in that text.\n", + "render_json": "{\n \"status\": \"not_a_claim\",\n \"claim\": \"\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"\",\n \"key_entities\": [],\n \"presumed_intent\": \"\",\n \"original_input\": \"What a lovely day.\",\n \"locations\": null\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__not_a_claim_beside_claims.json b/tests/fixtures/parity/expected/extract__not_a_claim_beside_claims.json new file mode 100644 index 0000000..05550a3 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__not_a_claim_beside_claims.json @@ -0,0 +1,24 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024.", + "presumed_intent": "Verify reported figures", + "status": "not_a_claim" + }, + "render": "Claim: Alpha rose 5% in 2024.\n\nVerify it: lenz verify \"Alpha rose 5% in 2024.\"\n", + "render_json": "{\n \"status\": \"not_a_claim\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024.\",\n \"locations\": null\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__ready_one_claim.json b/tests/fixtures/parity/expected/extract__ready_one_claim.json new file mode 100644 index 0000000..e65da3c --- /dev/null +++ b/tests/fixtures/parity/expected/extract__ready_one_claim.json @@ -0,0 +1,24 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, + "render": "Claim: Alpha rose 5% in 2024.\n\nVerify it: lenz verify \"Alpha rose 5% in 2024.\"\n", + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024.\",\n \"locations\": null\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__ready_several_claims.json b/tests/fixtures/parity/expected/extract__ready_several_claims.json new file mode 100644 index 0000000..df61eab --- /dev/null +++ b/tests/fixtures/parity/expected/extract__ready_several_claims.json @@ -0,0 +1,27 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, + "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n 2. Beta fell 3% last year.\n", + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__replay_later_200.json b/tests/fixtures/parity/expected/extract__replay_later_200.json new file mode 100644 index 0000000..df61eab --- /dev/null +++ b/tests/fixtures/parity/expected/extract__replay_later_200.json @@ -0,0 +1,27 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, + "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n 2. Beta fell 3% last year.\n", + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" +} diff --git a/tests/fixtures/parity/expected/extract__url_fetch_502_unreadable.json b/tests/fixtures/parity/expected/extract__url_fetch_502_unreadable.json new file mode 100644 index 0000000..7ce9984 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__url_fetch_502_unreadable.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Extraction failed", + "code": "extraction_failed", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Extraction failed\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Extraction failed", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Extraction failed", + "status": 502 + } + }, + "request_id": "", + "retry_after": null, + "status_code": 502, + "type": "LenzAPIError" + } +} diff --git a/tests/fixtures/parity/expected/extract__url_fetch_503_upstream.json b/tests/fixtures/parity/expected/extract__url_fetch_503_upstream.json new file mode 100644 index 0000000..01e9faf --- /dev/null +++ b/tests/fixtures/parity/expected/extract__url_fetch_503_upstream.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "The page could not be read right now. Please retry shortly.", + "code": "upstream_unavailable", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "The page could not be read right now. Please retry shortly.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "The page could not be read right now. Please retry shortly.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "The page could not be read right now. Please retry shortly.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 90, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/extract__url_input_located.json b/tests/fixtures/parity/expected/extract__url_input_located.json new file mode 100644 index 0000000..ca78e96 --- /dev/null +++ b/tests/fixtures/parity/expected/extract__url_input_located.json @@ -0,0 +1,35 @@ +{ + "dump": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "end": null, + "start": null, + "text": "Alpha rose 5% in 2024." + } + ] + } + ], + "original_input": "https://example.com/an-article", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, + "render": "Claim: Alpha rose 5% in 2024.\n at \"Alpha rose 5% in 2024.\"\n\nVerify it: lenz verify \"Alpha rose 5% in 2024.\"\n", + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"https://example.com/an-article\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": null,\n \"end\": null,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n }\n ]\n}\n" +} diff --git a/tests/fixtures/parity/expected/review__401_no_credentials.json b/tests/fixtures/parity/expected/review__401_no_credentials.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/review__401_no_credentials.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/review__402_no_credits.json b/tests/fixtures/parity/expected/review__402_no_credits.json new file mode 100644 index 0000000..6f8a31c --- /dev/null +++ b/tests/fixtures/parity/expected/review__402_no_credits.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "No remaining credits to assess the draft.", + "code": "no_credits", + "cost": 1, + "credit_balance": 100, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "No remaining credits to assess the draft.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "No remaining credits to assess the draft.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "No remaining credits to assess the draft.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 100, + "request_id": "", + "requested": null, + "resets_at": "2026-10-01T09:14:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/review__402_no_credits_exhausted.json b/tests/fixtures/parity/expected/review__402_no_credits_exhausted.json new file mode 100644 index 0000000..c98a94a --- /dev/null +++ b/tests/fixtures/parity/expected/review__402_no_credits_exhausted.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "No remaining credits to assess the draft.", + "code": "no_credits", + "cost": 1, + "credit_balance": 0, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "No remaining credits to assess the draft.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "No remaining credits to assess the draft.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "No remaining credits to assess the draft.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 0, + "request_id": "", + "requested": null, + "resets_at": "2026-10-01T09:14:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/review__422_blank_text.json b/tests/fixtures/parity/expected/review__422_blank_text.json new file mode 100644 index 0000000..2f05a24 --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_blank_text.json @@ -0,0 +1,30 @@ +{ + "error": { + "cause": "text: send the draft, or one public http(s) URL.", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "text" + ], + "msg": "text: send the draft, or one public http(s) URL." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "text: send the draft, or one public http(s) URL.\n Fix: Check the request body against the OpenAPI spec.", + "message": "text: send the draft, or one public http(s) URL.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "text: send the draft, or one public http(s) URL.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_citations_options_object.json b/tests/fixtures/parity/expected/review__422_citations_options_object.json new file mode 100644 index 0000000..eb82b86 --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_citations_options_object.json @@ -0,0 +1,31 @@ +{ + "error": { + "cause": "payload.citations: Extra inputs are not permitted", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "citations" + ], + "msg": "Extra inputs are not permitted" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.citations: Extra inputs are not permitted\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.citations: Extra inputs are not permitted", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.citations: Extra inputs are not permitted", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_depth_unknown.json b/tests/fixtures/parity/expected/review__422_depth_unknown.json new file mode 100644 index 0000000..c4709d8 --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_depth_unknown.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.escalate.depth: Input should be 'standard' or 'low'", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "depth" + ], + "msg": "Input should be 'standard' or 'low'" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.escalate.depth: Input should be 'standard' or 'low'\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.escalate.depth: Input should be 'standard' or 'low'", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.escalate.depth: Input should be 'standard' or 'low'", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_invalid_confidence_band.json b/tests/fixtures/parity/expected/review__422_invalid_confidence_band.json new file mode 100644 index 0000000..6d1bc1b --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_invalid_confidence_band.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.escalate.confidence: Unknown confidence band 'certain'; use low, medium or high.", + "code": "invalid_confidence_band", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "confidence" + ], + "msg": "Unknown confidence band 'certain'; use low, medium or high." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.escalate.confidence: Unknown confidence band 'certain'; use low, medium or high.\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.escalate.confidence: Unknown confidence band 'certain'; use low, medium or high.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.escalate.confidence: Unknown confidence band 'certain'; use low, medium or high.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_invalid_verdict_label.json b/tests/fixtures/parity/expected/review__422_invalid_verdict_label.json new file mode 100644 index 0000000..27f708f --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_invalid_verdict_label.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.escalate.verdicts: Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True.", + "code": "invalid_verdict_label", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "verdicts" + ], + "msg": "Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.escalate.verdicts: Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True.\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.escalate.verdicts: Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.escalate.verdicts: Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_max_assessments_negative.json b/tests/fixtures/parity/expected/review__422_max_assessments_negative.json new file mode 100644 index 0000000..190d110 --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_max_assessments_negative.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.escalate.max_assessments: Input should be greater than or equal to 0", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_assessments" + ], + "msg": "Input should be greater than or equal to 0" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.escalate.max_assessments: Input should be greater than or equal to 0\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.escalate.max_assessments: Input should be greater than or equal to 0", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.escalate.max_assessments: Input should be greater than or equal to 0", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_max_citations_negative.json b/tests/fixtures/parity/expected/review__422_max_citations_negative.json new file mode 100644 index 0000000..cf456cf --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_max_citations_negative.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.escalate.max_citations: Input should be greater than or equal to 0", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_citations" + ], + "msg": "Input should be greater than or equal to 0" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.escalate.max_citations: Input should be greater than or equal to 0\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.escalate.max_citations: Input should be greater than or equal to 0", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.escalate.max_citations: Input should be greater than or equal to 0", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_max_citations_too_big.json b/tests/fixtures/parity/expected/review__422_max_citations_too_big.json new file mode 100644 index 0000000..4888a1c --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_max_citations_too_big.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.escalate.max_citations: Input should be less than or equal to 20", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_citations" + ], + "msg": "Input should be less than or equal to 20" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.escalate.max_citations: Input should be less than or equal to 20\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.escalate.max_citations: Input should be less than or equal to 20", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.escalate.max_citations: Input should be less than or equal to 20", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_max_verifications_too_big.json b/tests/fixtures/parity/expected/review__422_max_verifications_too_big.json new file mode 100644 index 0000000..88ecb6e --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_max_verifications_too_big.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.escalate.max_verifications: Input should be less than or equal to 20", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_verifications" + ], + "msg": "Input should be less than or equal to 20" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.escalate.max_verifications: Input should be less than or equal to 20\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.escalate.max_verifications: Input should be less than or equal to 20", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.escalate.max_verifications: Input should be less than or equal to 20", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_text_missing.json b/tests/fixtures/parity/expected/review__422_text_missing.json new file mode 100644 index 0000000..627bead --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_text_missing.json @@ -0,0 +1,31 @@ +{ + "error": { + "cause": "payload.text: Field required", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.text: Field required\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.text: Field required", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.text: Field required", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_text_wrong_type.json b/tests/fixtures/parity/expected/review__422_text_wrong_type.json new file mode 100644 index 0000000..66dd498 --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_text_wrong_type.json @@ -0,0 +1,31 @@ +{ + "error": { + "cause": "payload.text: Input should be a valid string", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Input should be a valid string" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.text: Input should be a valid string\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.text: Input should be a valid string", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.text: Input should be a valid string", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_unknown_escalate_field.json b/tests/fixtures/parity/expected/review__422_unknown_escalate_field.json new file mode 100644 index 0000000..78a92fb --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_unknown_escalate_field.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "payload.escalate.nope: Extra inputs are not permitted", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "nope" + ], + "msg": "Extra inputs are not permitted" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.escalate.nope: Extra inputs are not permitted\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.escalate.nope: Extra inputs are not permitted", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.escalate.nope: Extra inputs are not permitted", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_unknown_top_level_field.json b/tests/fixtures/parity/expected/review__422_unknown_top_level_field.json new file mode 100644 index 0000000..110cec7 --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_unknown_top_level_field.json @@ -0,0 +1,31 @@ +{ + "error": { + "cause": "payload.max_verifications: Extra inputs are not permitted", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "max_verifications" + ], + "msg": "Extra inputs are not permitted" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.max_verifications: Extra inputs are not permitted\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.max_verifications: Extra inputs are not permitted", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.max_verifications: Extra inputs are not permitted", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_unsupported_language.json b/tests/fixtures/parity/expected/review__422_unsupported_language.json new file mode 100644 index 0000000..f15e35e --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_unsupported_language.json @@ -0,0 +1,30 @@ +{ + "error": { + "cause": "language: Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "language" + ], + "msg": "language: Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "language: Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.\n Fix: Check the request body against the OpenAPI spec.", + "message": "language: Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "language: Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__422_visibility_public.json b/tests/fixtures/parity/expected/review__422_visibility_public.json new file mode 100644 index 0000000..a4c768d --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_visibility_public.json @@ -0,0 +1,31 @@ +{ + "error": { + "cause": "payload.visibility: Input should be 'private' or 'unlisted'", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "visibility" + ], + "msg": "Input should be 'private' or 'unlisted'" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "payload.visibility: Input should be 'private' or 'unlisted'\n Fix: Check the request body against the OpenAPI spec.", + "message": "payload.visibility: Input should be 'private' or 'unlisted'", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "payload.visibility: Input should be 'private' or 'unlisted'", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__429_extract_daily_limit.json b/tests/fixtures/parity/expected/review__429_extract_daily_limit.json new file mode 100644 index 0000000..9486b2b --- /dev/null +++ b/tests/fixtures/parity/expected/review__429_extract_daily_limit.json @@ -0,0 +1,25 @@ +{ + "error": { + "cause": "Daily /extract limit of 1000 reached for this account. A review of a URL reads the page like /extract and counts as one /extract call.", + "code": "extract_daily_limit", + "doc_url": "https://lenz.io/docs/rate-limits", + "fix": "Wait Retry-After seconds and retry.", + "friendly_text": "Daily /extract limit of 1000 reached for this account. A review of a URL reads the page like /extract and counts as one /extract call.\n Fix: Wait Retry-After seconds and retry.", + "limit": 1000, + "message": "Daily /extract limit of 1000 reached for this account. A review of a URL reads the page like /extract and counts as one /extract call.", + "payload_json": { + "error": { + "code": "rate_limited", + "fix": "Wait Retry-After seconds and retry.", + "message": "Daily /extract limit of 1000 reached for this account. A review of a URL reads the page like /extract and counts as one /extract call.", + "status": 429 + } + }, + "request_id": "", + "reset_in_seconds": 60, + "retry_after": 60, + "status_code": 429, + "type": "LenzRateLimitError", + "upgrade_url": "https://lenz.io/plans" + } +} diff --git a/tests/fixtures/parity/expected/review__429_review_in_flight.json b/tests/fixtures/parity/expected/review__429_review_in_flight.json new file mode 100644 index 0000000..2d14064 --- /dev/null +++ b/tests/fixtures/parity/expected/review__429_review_in_flight.json @@ -0,0 +1,25 @@ +{ + "error": { + "cause": "This account already has 3 reviews running. Retry when one completes.", + "code": "review_in_flight", + "doc_url": "https://lenz.io/docs/rate-limits", + "fix": "Wait Retry-After seconds and retry.", + "friendly_text": "This account already has 3 reviews running. Retry when one completes.\n Fix: Wait Retry-After seconds and retry.", + "limit": null, + "message": "This account already has 3 reviews running. Retry when one completes.", + "payload_json": { + "error": { + "code": "rate_limited", + "fix": "Wait Retry-After seconds and retry.", + "message": "This account already has 3 reviews running. Retry when one completes.", + "status": 429 + } + }, + "request_id": "", + "reset_in_seconds": null, + "retry_after": 60, + "status_code": 429, + "type": "LenzRateLimitError", + "upgrade_url": "" + } +} diff --git a/tests/fixtures/parity/expected/review__503_capacity.json b/tests/fixtures/parity/expected/review__503_capacity.json new file mode 100644 index 0000000..5384727 --- /dev/null +++ b/tests/fixtures/parity/expected/review__503_capacity.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 90, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/review__503_citations_capacity.json b/tests/fixtures/parity/expected/review__503_citations_capacity.json new file mode 100644 index 0000000..5384727 --- /dev/null +++ b/tests/fixtures/parity/expected/review__503_citations_capacity.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "status": 503 + } + }, + "request_id": "", + "retry_after": 90, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/review__get_403_insufficient_scope.json b/tests/fixtures/parity/expected/review__get_403_insufficient_scope.json new file mode 100644 index 0000000..567f3ae --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_403_insufficient_scope.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "The access token does not allow this call.", + "code": "insufficient_scope", + "doc_url": "https://lenz.io/docs/auth", + "fix": "This key doesn't have access to that resource.", + "friendly_text": "The access token does not allow this call.\n Fix: This key doesn't have access to that resource.", + "message": "The access token does not allow this call.", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "This key doesn't have access to that resource.", + "message": "The access token does not allow this call.", + "status": 403 + } + }, + "request_id": "", + "status_code": 403, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/review__get_404_not_found.json b/tests/fixtures/parity/expected/review__get_404_not_found.json new file mode 100644 index 0000000..528e617 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_404_not_found.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Review not found.", + "code": "not_found", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Review not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Review not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Review not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/review__get_404_other_account.json b/tests/fixtures/parity/expected/review__get_404_other_account.json new file mode 100644 index 0000000..528e617 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_404_other_account.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Review not found.", + "code": "not_found", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Review not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Review not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Review not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/review__get_410_purged.json b/tests/fixtures/parity/expected/review__get_410_purged.json new file mode 100644 index 0000000..57658a2 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_410_purged.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "This review is no longer available: its account removes content after a set period.", + "code": "purged", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Its account's retention period removed it. A certificate issued for it is still available.", + "friendly_text": "This review is no longer available: its account removes content after a set period.\n Fix: Its account's retention period removed it. A certificate issued for it is still available.", + "message": "This review is no longer available: its account removes content after a set period.", + "payload_json": { + "error": { + "code": "gone", + "fix": "Its account's retention period removed it. A certificate issued for it is still available.", + "message": "This review is no longer available: its account removes content after a set period.", + "status": 410 + } + }, + "purged_at": "2026-10-01T09:07:00.123456Z", + "request_id": "", + "status_code": 410, + "type": "LenzGoneError" + } +} diff --git a/tests/fixtures/parity/expected/review__get_422_unknown_view.json b/tests/fixtures/parity/expected/review__get_422_unknown_view.json new file mode 100644 index 0000000..7d2cc01 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_422_unknown_view.json @@ -0,0 +1,30 @@ +{ + "error": { + "cause": "view: use full or issues.", + "code": "validation_error", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "query", + "view" + ], + "msg": "view: use full or issues." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "view: use full or issues.\n Fix: Check the request body against the OpenAPI spec.", + "message": "view: use full or issues.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "view: use full or issues.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__get_assessing.json b/tests/fixtures/parity/expected/review__get_assessing.json new file mode 100644 index 0000000..72f3ffc --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_assessing.json @@ -0,0 +1,108 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "running", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": null, + "index": 0, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "running", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": null, + "index": 1, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 10, + "review_id": "d6b2bd72", + "status": "assessing", + "summary": { + "assessments": { + "completed": 0, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: assessing — 2 claims: 2 not checked · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n ? · quick check\n\n[2/2] Water boils at 100 C at sea level.\n ? · quick check\n", + "render_issues": "Review d6b2bd72: assessing — 2 claims: 2 not checked · 2 credits charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_assessment_rows_full_fields.json b/tests/fixtures/parity/expected/review__get_assessment_rows_full_fields.json new file mode 100644 index 0000000..8322f9e --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_assessment_rows_full_fields.json @@ -0,0 +1,168 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": "One reviewer read the claim as about the entry into force.", + "error_code": null, + "failure": null, + "hint": "This text holds more than one claim.", + "identified_claims": [ + "The EU AI Act took effect in 2024.", + "It took effect in March." + ], + "rationale": "Two reviewers found the date wrong.", + "status": "completed", + "suggested_rewrite": "The EU AI Act entered into force in August 2024.", + "verdict": "False", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "cap", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "assessment", + "verdict": "False" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": "timeout", + "failure": { + "docs_url": null, + "failure_class": "upstream_unavailable", + "failure_reason": "timeout", + "hint": "The check ran out of time. Retry it; nothing was charged.", + "retryable": true + }, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "failed", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": null, + "index": 1, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 1, + "failure": { + "docs_url": null, + "failure_class": "upstream_unavailable", + "failure_reason": "timeout", + "hint": "The check ran out of time. Retry it; nothing was charged.", + "retryable": true + }, + "stage": "assessment" + } + ], + "issues": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "cap", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": null, + "rationale": "Two reviewers found the date wrong.", + "source": "assessment", + "suggested_edits": null, + "suggested_rewrite": "The EU AI Act entered into force in August 2024.", + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": null, + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "incomplete", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 0, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 1 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: incomplete — 2 claims: 1 issue, 1 failed · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n Two reviewers found the date wrong.\n Not deep-checked (cap).\n\n[2/2] The Eiffel Tower is in Berlin.\n Quick check failed: The check ran out of time. Retry it; nothing was charged.\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: incomplete — 2 claims: 1 issue, 1 failed · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n Two reviewers found the date wrong.\n Suggested rewrite: The EU AI Act entered into force in August 2024.\n Not deep-checked (cap).\n\n[2/2] The Eiffel Tower is in Berlin.\n Assessment failed: The check ran out of time. Retry it; nothing was charged.\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_clean.json b/tests/fixtures/parity/expected/review__get_citations_clean.json new file mode 100644 index 0000000..b9ecbce --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_clean.json @@ -0,0 +1,181 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 3 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n2 checked.\n", + "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n2 checked.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_failed_and_unchecked.json b/tests/fixtures/parity/expected/review__get_citations_failed_and_unchecked.json new file mode 100644 index 0000000..81f36b2 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_failed_and_unchecked.json @@ -0,0 +1,197 @@ +{ + "dump": { + "citation_failures": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#internal", + "failure_class": "internal", + "failure_reason": "internal", + "hint": "The check failed on our side. Try again later.", + "retryable": false + }, + "reference": "a report from the ministry" + } + ], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#internal", + "failure_class": "internal", + "failure_reason": "internal", + "hint": "The check failed on our side. Try again later.", + "retryable": false + }, + "hint": "The check failed on our side. Try again later.", + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "failed", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": null, + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "unchecked", + "unchecked_reason": "no_text" + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "unchecked", + "is_issue": false, + "source": null + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "incomplete", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 0, + "failed": 1, + "unchecked": 1 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: incomplete — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n2 could not be checked.\n\n[source 1/2] Could not be checked this time.\n https://example.gov/report-2024\n The check failed on our side. Try again later.\n\nCheck these by hand (Lenz could not check them)\n[source 2/2] The page gave no text to read.\n https://example.org/statement\n", + "render_issues": "Review d6b2bd72: incomplete — 1 claim: 1 true or mostly true · 1 credit charged\n\n2 sources cited in your draft\n2 could not be checked.\n\n[source 1/2] Could not be checked this time.\n https://example.gov/report-2024\n The check failed on our side. Try again later.\n\nCheck these by hand (Lenz could not check them)\n[source 2/2] The page gave no text to read.\n https://example.org/statement\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_issue_full.json b/tests/fixtures/parity/expected/review__get_citations_issue_full.json new file mode 100644 index 0000000..cbb418a --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_issue_full.json @@ -0,0 +1,203 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": null, + "finding": "contradicted", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "rationale": "The page states it.", + "reference": "a report from the ministry", + "snippet": "The source says so.", + "source": "support", + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + } + ], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "contradicted", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "contradicted", + "is_issue": true, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 3 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 1, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 1, + "render": "Review d6b2bd72: issues found — 1 claim: 1 true or mostly true · 3 credits charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n2 checked, 1 with a problem.\n\n[source 1/2] Contradicted\n Unemployment fell to 4.1% in 2024, according to a report from the ministry.\n https://example.gov/report-2024\n The source says:\n “The source says so.”\n Reviewer's note: The page states it.\n\nA reviewer's note is reasoning, not a checked source; the quoted passage is from the page.\n", + "render_issues": "Review d6b2bd72: issues found — 1 claim: 1 true or mostly true · 3 credits charged\n\n2 sources cited in your draft\n2 checked, 1 with a problem.\n\n[source 1/2] Contradicted\n Unemployment fell to 4.1% in 2024, according to a report from the ministry.\n https://example.gov/report-2024\n The source says:\n “The source says so.”\n Reviewer's note: The page states it.\n\nA reviewer's note is reasoning, not a checked source; the quoted passage is from the page.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_issue_issues_view.json b/tests/fixtures/parity/expected/review__get_citations_issue_issues_view.json new file mode 100644 index 0000000..59abdb7 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_issue_issues_view.json @@ -0,0 +1,93 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": null, + "finding": "contradicted", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "rationale": "The page states it.", + "reference": "a report from the ministry", + "snippet": "The source says so.", + "source": "support", + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + } + ], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 3 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 1, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "issues" + }, + "exit_code": 1, + "render": "Review d6b2bd72: issues found — 1 claim: 1 not checked · 3 credits charged\n\n2 sources cited in your draft\n2 checked, 1 with a problem.\n\n[source 1/2] Contradicted\n Unemployment fell to 4.1% in 2024, according to a report from the ministry.\n https://example.gov/report-2024\n The source says:\n “The source says so.”\n Reviewer's note: The page states it.\n\nA reviewer's note is reasoning, not a checked source; the quoted passage is from the page.\n", + "render_issues": "Review d6b2bd72: issues found — 1 claim: 1 not checked · 3 credits charged\n\n2 sources cited in your draft\n2 checked, 1 with a problem.\n\n[source 1/2] Contradicted\n Unemployment fell to 4.1% in 2024, according to a report from the ministry.\n https://example.gov/report-2024\n The source says:\n “The source says so.”\n Reviewer's note: The page states it.\n\nA reviewer's note is reasoning, not a checked source; the quoted passage is from the page.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_limit_exactly_at_limit.json b/tests/fixtures/parity/expected/review__get_citations_limit_exactly_at_limit.json new file mode 100644 index 0000000..21955f5 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_limit_exactly_at_limit.json @@ -0,0 +1,181 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 3 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 2, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n2 checked.\n", + "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n2 checked.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_limit_reached.json b/tests/fixtures/parity/expected/review__get_citations_limit_reached.json new file mode 100644 index 0000000..5e3bb88 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_limit_reached.json @@ -0,0 +1,155 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [ + { + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "reference": "a statement", + "sentence": "The agency said so in a statement." + } + ], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 1, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 1, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 1, + "citation_limit_reached": true, + "citations_found": 2, + "citations_selected": 1, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 2 credits charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n1 checked.\n1 more was not checked: one check covers 1.\n\n1 more citation was found but not checked.\n", + "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 2 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n1 checked.\n1 more was not checked: one check covers 1.\n\n1 more citation was found but not checked.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_no_claim_but_citations.json b/tests/fixtures/parity/expected/review__get_citations_no_claim_but_citations.json new file mode 100644 index 0000000..8093baf --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_no_claim_but_citations.json @@ -0,0 +1,150 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 0, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 0, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — no claims checked · 2 credits charged\n\n2 sources cited in your draft\n2 checked.\n", + "render_issues": "Review d6b2bd72: clean — no claims checked · 2 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n2 checked.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_no_claim_no_citation.json b/tests/fixtures/parity/expected/review__get_citations_no_claim_no_citation.json new file mode 100644 index 0000000..c088cac --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_no_claim_no_citation.json @@ -0,0 +1,66 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "no_claim", + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", + "retryable": false + }, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": "unchecked", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "failed", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run\nthe text through /extract to enumerate its claims.\n", + "render_issues": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run\nthe text through /extract to enumerate its claims.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_not_asked.json b/tests/fixtures/parity/expected/review__get_citations_not_asked.json new file mode 100644 index 0000000..a7c1d4a --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_not_asked.json @@ -0,0 +1,98 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_only.json b/tests/fixtures/parity/expected/review__get_citations_only.json new file mode 100644 index 0000000..ec2968f --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_only.json @@ -0,0 +1,157 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "positions": null + } + ], + "more_claims": [ + "The EU AI Act took effect in March 2024." + ], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 0, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 0, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 0, + "claim_limit_reached": true, + "claims_selected": 0, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — no claims checked · 2 credits charged\n\n2 sources cited in your draft\n2 checked.\n\n1 more claim was found but not checked.\n", + "render_issues": "Review d6b2bd72: clean — no claims checked · 2 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n2 checked.\n\n1 more claim was found but not checked.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_partly_supported.json b/tests/fixtures/parity/expected/review__get_citations_partly_supported.json new file mode 100644 index 0000000..1f7c6fc --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_partly_supported.json @@ -0,0 +1,181 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "partly_supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "partly_supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 3 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n2 checked.\n", + "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n2 checked.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_running.json b/tests/fixtures/parity/expected/review__get_citations_running.json new file mode 100644 index 0000000..197c7ad --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_running.json @@ -0,0 +1,165 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "pending", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "a report from the ministry", + "result": null, + "statement": null + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "pending", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "a statement", + "result": null, + "statement": null + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 15, + "review_id": "d6b2bd72", + "status": "verifying", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 0, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: verifying — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\nLenz checks each one: does the source say what your draft says it does.\n", + "render_issues": "Review d6b2bd72: verifying — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n\n2 sources cited in your draft\nLenz checks each one: does the source say what your draft says it does.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_skipped_switched_off.json b/tests/fixtures/parity/expected/review__get_citations_skipped_switched_off.json new file mode 100644 index 0000000..9656e4e --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_skipped_switched_off.json @@ -0,0 +1,98 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": "switched_off", + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_citations_skipped_url_input.json b/tests/fixtures/parity/expected/review__get_citations_skipped_url_input.json new file mode 100644 index 0000000..4a4d436 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_citations_skipped_url_input.json @@ -0,0 +1,66 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": null, + "retryable": true + }, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": "unchecked", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "failed", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": "url_input", + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: upstream_unavailable\n\nSources on a linked page are not checked. Paste the page's text instead to check them.\n", + "render_issues": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: upstream_unavailable\n\nSources on a linked page are not checked. Paste the page's text instead to check them.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_claim_limit_not_reached.json b/tests/fixtures/parity/expected/review__get_claim_limit_not_reached.json new file mode 100644 index 0000000..fe88fdc --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_claim_limit_not_reached.json @@ -0,0 +1,128 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 3, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 3, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n[2/2] Water boils at 100 C at sea level.\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_claim_limit_reached_exact.json b/tests/fixtures/parity/expected/review__get_claim_limit_reached_exact.json new file mode 100644 index 0000000..50f547c --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_claim_limit_reached_exact.json @@ -0,0 +1,128 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 2, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 2, + "claim_limit_reached": true, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n[2/2] Water boils at 100 C at sea level.\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_completed_assess_only.json b/tests/fixtures/parity/expected/review__get_completed_assess_only.json new file mode 100644 index 0000000..382a665 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_completed_assess_only.json @@ -0,0 +1,154 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "cap", + "matched_rules": [ + "verdict" + ] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "assessment", + "verdict": "False" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 1, + "confidence": "high", + "escalation": { + "disposition": "cap", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": null, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": null, + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 0, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 1, + "render": "Review d6b2bd72: issues found — 2 claims: 1 issue, 1 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n[2/2] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Not deep-checked (cap).\n", + "render_issues": "Review d6b2bd72: issues found — 2 claims: 1 issue, 1 true or mostly true · 2 credits charged\n\n[2/2] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Not deep-checked (cap).\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_completed_clean.json b/tests/fixtures/parity/expected/review__get_completed_clean.json new file mode 100644 index 0000000..b028662 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_completed_clean.json @@ -0,0 +1,128 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Paris is the capital of France.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n[2/2] Paris is the capital of France.\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_completed_issues_all_verified.json b/tests/fixtures/parity/expected/review__get_completed_issues_all_verified.json new file mode 100644 index 0000000..aa86f83 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_completed_issues_all_verified.json @@ -0,0 +1,259 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "medium", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "Mostly False", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The EU AI Act took effect in March 2024.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T09:49:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The EU AI Act took effect in March 2024.", + "failure": null, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "task_id": "c010dca9a43543f518e49f4ec7842ceb", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verdict": "False", + "verification_id": "b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "visibility": "private", + "warnings": [ + "w1" + ] + } + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T09:49:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "task_id": "4634b89821fd877f1edf8aaeb82b7ee5", + "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "verdict": "False", + "verification_id": "b79019e4", + "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", + "visibility": "private", + "warnings": [ + "w1" + ] + } + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Paris is the capital of France.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 2, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 23 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verdict": "False", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verified_claim": null + }, + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 1, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "verdict": "False", + "verification_id": "b79019e4", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 3, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 3, + "input_truncated": false, + "issues": 2, + "verifications": { + "completed": 2, + "failed": 0, + "planned": 2 + } + }, + "view": "full" + }, + "exit_code": 1, + "render": "Review d6b2bd72: issues found — 3 claims: 2 issues, 1 true or mostly true · 2 of 2 deep-checked · 23 credits charged\n\n[1/3] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\n[2/3] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b79019e4\n\n[3/3] Paris is the capital of France.\n True (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: issues found — 3 claims: 2 issues, 1 true or mostly true · 2 of 2 deep-checked · 23 credits charged\n\n[1/3] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\n[2/3] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b79019e4\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_completed_issues_full.json b/tests/fixtures/parity/expected/review__get_completed_issues_full.json new file mode 100644 index 0000000..b2bfc03 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_completed_issues_full.json @@ -0,0 +1,310 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "medium", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "Mostly False", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The EU AI Act took effect in March 2024.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T09:42:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The EU AI Act took effect in March 2024.", + "failure": null, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "task_id": "7df4009bc27aab64ce5d5a01fbafe599", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verdict": "False", + "verification_id": "b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "visibility": "private", + "warnings": [ + "w1" + ] + } + }, + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": "upstream_unavailable", + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "failed", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": null, + "index": 1, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 2, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "assessment", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": null, + "confidence": null, + "content_status": "available", + "created_at": null, + "depth": null, + "domain": null, + "entities": [], + "executive_summary": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "hint": null, + "retryable": false + }, + "key_finding": null, + "language": null, + "lenz_score": null, + "modified_at": null, + "status": "failed", + "suggested_rewrite": null, + "task_id": "5ccac77f53ff49328ec134fb29d66542", + "url": null, + "verdict": null, + "verification_id": null, + "verification_url": null, + "visibility": null, + "warnings": [] + } + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Paris is the capital of France.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 3, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 13 + }, + "failure": null, + "failures": [ + { + "claim": "Water boils at 100 C at sea level.", + "claim_index": 1, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "stage": "assessment" + } + ], + "issues": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verdict": "False", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verified_claim": null + }, + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 2, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "hint": null, + "retryable": false + }, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": null, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": "failed", + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "incomplete", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 3, + "failed": 1 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 4, + "input_truncated": false, + "issues": 2, + "verifications": { + "completed": 1, + "failed": 1, + "planned": 2 + } + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 true or mostly true, 1 failed · 1 of 2 deep-checked · 13 credits \ncharged\n\n[1/4] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\n[2/4] Water boils at 100 C at sea level.\n Quick check failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\n[3/4] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Deep check failed: The deep check failed.\n\n[4/4] Paris is the capital of France.\n True (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 true or mostly true, 1 failed · 1 of 2 deep-checked · 13 credits \ncharged\n\n[1/4] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\n[3/4] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Deep check failed: research_empty\n\n[2/4] Water boils at 100 C at sea level.\n Assessment failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_completed_issues_view_issues.json b/tests/fixtures/parity/expected/review__get_completed_issues_view_issues.json new file mode 100644 index 0000000..c0c2c56 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_completed_issues_view_issues.json @@ -0,0 +1,133 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 13 + }, + "failure": null, + "failures": [ + { + "claim": "Water boils at 100 C at sea level.", + "claim_index": 1, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "stage": "assessment" + } + ], + "issues": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verdict": "False", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verified_claim": null + }, + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 2, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "hint": null, + "retryable": false + }, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": null, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": "failed", + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "incomplete", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 3, + "failed": 1 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 4, + "input_truncated": false, + "issues": 2, + "verifications": { + "completed": 1, + "failed": 1, + "planned": 2 + } + }, + "view": "issues" + }, + "exit_code": 2, + "render": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 failed, 1 not checked · 1 of 2 deep-checked · 13 credits charged\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 failed, 1 not checked · 1 of 2 deep-checked · 13 credits charged\n\n[1/4] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\n[3/4] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Deep check failed: research_empty\n\n[2/4] Water boils at 100 C at sea level.\n Assessment failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_completed_positions.json b/tests/fixtures/parity/expected/review__get_completed_positions.json new file mode 100644 index 0000000..f89f5be --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_completed_positions.json @@ -0,0 +1,140 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": [ + { + "end": 40, + "start": 0, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": [ + { + "end": 89, + "start": 55, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024. · at 0-40\n True (high) · quick check\n\n[2/2] Water boils at 100 C at sea level. · at 55-89\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_completed_recovered_claim.json b/tests/fixtures/parity/expected/review__get_completed_recovered_claim.json new file mode 100644 index 0000000..dde95e1 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_completed_recovered_claim.json @@ -0,0 +1,98 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Orbit Motors stock increased by 40% in 2022.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": [], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] Orbit Motors stock increased by 40% in 2022.\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_completed_with_untraced_claim.json b/tests/fixtures/parity/expected/review__get_completed_with_untraced_claim.json new file mode 100644 index 0000000..cdb1fd6 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_completed_with_untraced_claim.json @@ -0,0 +1,140 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": [ + { + "end": 40, + "start": 0, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": [ + { + "end": 84, + "start": 50, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024. · at 0-40\n True (high) · quick check\n\n[2/2] Water boils at 100 C at sea level. · at 50-84\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_during_quick_check.json b/tests/fixtures/parity/expected/review__get_during_quick_check.json new file mode 100644 index 0000000..efe850f --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_during_quick_check.json @@ -0,0 +1,86 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "running", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": null, + "index": 0, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 10, + "review_id": "d6b2bd72", + "status": "assessing", + "summary": { + "assessments": { + "completed": 0, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: assessing — 1 claim: 1 not checked · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n ? · quick check\n", + "render_issues": "Review d6b2bd72: assessing — 1 claim: 1 not checked · 1 credit charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_failed_every_assessment_failed.json b/tests/fixtures/parity/expected/review__get_failed_every_assessment_failed.json new file mode 100644 index 0000000..d9d5414 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_failed_every_assessment_failed.json @@ -0,0 +1,155 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": "upstream_unavailable", + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "failed", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": null, + "index": 0, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": "upstream_unavailable", + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "failed", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": null, + "index": 1, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "assessment_failed", + "hint": "No claim could be assessed. Retry the review with a new Idempotency-Key; nothing was charged.", + "retryable": true + }, + "failures": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "stage": "assessment" + }, + { + "claim": "Water boils at 100 C at sea level.", + "claim_index": 1, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "stage": "assessment" + } + ], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "incomplete", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "failed", + "summary": { + "assessments": { + "completed": 0, + "failed": 2 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: incomplete — 2 claims: 2 failed · 0 credits charged\nFailed: No claim could be assessed. Retry the review with a new Idempotency-Key; nothing was charged.\n\n[1/2] The EU AI Act took effect in March 2024.\n Quick check failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\n[2/2] Water boils at 100 C at sea level.\n Quick check failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n", + "render_issues": "Review d6b2bd72: incomplete — 2 claims: 2 failed · 0 credits charged\nFailed: No claim could be assessed. Retry the review with a new Idempotency-Key; nothing was charged.\n\n[1/2] The EU AI Act took effect in March 2024.\n Assessment failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\n[2/2] Water boils at 100 C at sea level.\n Assessment failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_failed_no_claim.json b/tests/fixtures/parity/expected/review__get_failed_no_claim.json new file mode 100644 index 0000000..8a2a3a1 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_failed_no_claim.json @@ -0,0 +1,66 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "no_claim", + "hint": "The text is a greeting, not a statement about the world. Send one factual claim, or run the text through /extract to enumerate its claims.", + "retryable": false + }, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": "unchecked", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "failed", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: The text is a greeting, not a statement about the world. Send one factual claim, or run the text through \n/extract to enumerate its claims.\n", + "render_issues": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: The text is a greeting, not a statement about the world. Send one factual claim, or run the text through \n/extract to enumerate its claims.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_failed_no_claim_untraced.json b/tests/fixtures/parity/expected/review__get_failed_no_claim_untraced.json new file mode 100644 index 0000000..435f4a6 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_failed_no_claim_untraced.json @@ -0,0 +1,66 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "no_claim", + "hint": "None of the claims found in the text could be traced back to it. Send one factual claim, or run the text through /extract to enumerate its claims.", + "retryable": false + }, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": "unchecked", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "failed", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: None of the claims found in the text could be traced back to it. Send one factual claim, or run the text through\n/extract to enumerate its claims.\n", + "render_issues": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: None of the claims found in the text could be traced back to it. Send one factual claim, or run the text through\n/extract to enumerate its claims.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_more_claims.json b/tests/fixtures/parity/expected/review__get_more_claims.json new file mode 100644 index 0000000..e22d03e --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_more_claims.json @@ -0,0 +1,153 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": [ + { + "end": 40, + "start": 0, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": [ + { + "end": 84, + "start": 50, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "positions": [ + { + "end": 121, + "start": 91, + "text": "The Eiffel Tower is in Berlin." + } + ] + } + ], + "more_claims": [ + "The Eiffel Tower is in Berlin." + ], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 2, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 2, + "claim_limit_reached": true, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024. · at 0-40\n True (high) · quick check\n\n[2/2] Water boils at 100 C at sea level. · at 50-84\n True (high) · quick check\n\n1 more claim was found but not checked.\n", + "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n\n1 more claim was found but not checked.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..56e09af --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,149 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "language": "en", + "lenz_score": 2, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "status": "completed", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "task_id": "7df4009bc27aab64ce5d5a01fbafe599", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verdict": "False", + "verification_id": "b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "visibility": "private", + "warnings": [ + "w1" + ] + } + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 11 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verdict": "False", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 1, + "failed": 0, + "planned": 1 + } + }, + "view": "full" + }, + "exit_code": 1, + "render": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..ac41e67 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_same_day_hours_apart.json @@ -0,0 +1,149 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "task_id": "7df4009bc27aab64ce5d5a01fbafe599", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verdict": "False", + "verification_id": "b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "visibility": "private", + "warnings": [ + "w1" + ] + } + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 11 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verdict": "False", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 1, + "failed": 0, + "planned": 1 + } + }, + "view": "full" + }, + "exit_code": 1, + "render": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_policy_resolved.json b/tests/fixtures/parity/expected/review__get_policy_resolved.json new file mode 100644 index 0000000..d49a7f7 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_policy_resolved.json @@ -0,0 +1,96 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "low", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 2, + "suggest_edits": false, + "verdicts": [ + "False" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_queued.json b/tests/fixtures/parity/expected/review__get_queued.json new file mode 100644 index 0000000..00606b0 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_queued.json @@ -0,0 +1,60 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 10, + "review_id": "d6b2bd72", + "status": "queued", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: queued — no claims checked · 0 credits charged\n", + "render_issues": "Review d6b2bd72: queued — no claims checked · 0 credits charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_suggested_edits.json b/tests/fixtures/parity/expected/review__get_suggested_edits.json new file mode 100644 index 0000000..9624e1d --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_suggested_edits.json @@ -0,0 +1,267 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": [ + { + "end": 30, + "start": 0, + "text": "The Eiffel Tower is in Berlin." + } + ], + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": { + "edits": [ + { + "end": 29, + "position": 0, + "replacement": "Paris", + "start": 23, + "text": "Berlin" + } + ], + "status": "completed" + }, + "verification": { + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T09:35:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "task_id": "9bca1e0819de60a750186e812dc58e2b", + "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "verdict": "False", + "verification_id": "7c83247c", + "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "visibility": "private", + "warnings": [ + "w1" + ] + } + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 1, + "positions": [ + { + "end": 85, + "start": 45, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "confidence": "high", + "is_issue": true, + "source": "assessment", + "verdict": "False" + }, + "suggested_edits": { + "edits": null, + "status": "pending" + }, + "verification": { + "claim": null, + "confidence": null, + "content_status": "available", + "created_at": null, + "depth": null, + "domain": null, + "entities": [], + "executive_summary": null, + "failure": null, + "key_finding": null, + "language": null, + "lenz_score": null, + "modified_at": null, + "status": "processing", + "suggested_rewrite": null, + "task_id": null, + "url": null, + "verdict": null, + "verification_id": null, + "verification_url": null, + "visibility": null, + "warnings": [] + } + } + ], + "completed_at": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 12 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": { + "edits": [ + { + "end": 29, + "position": 0, + "replacement": "Paris", + "start": 23, + "text": "Berlin" + } + ], + "status": "completed" + }, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "verdict": "False", + "verification_id": "7c83247c", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "verified_claim": null + }, + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 1, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": { + "edits": null, + "status": "pending" + }, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": true, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 15, + "review_id": "d6b2bd72", + "status": "verifying", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 2, + "verifications": { + "completed": 1, + "failed": 0, + "planned": 2 + } + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\n[1/2] The Eiffel Tower is in Berlin. · at 0-30\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-7c83247c\n\n[2/2] The EU AI Act took effect in March 2024. · at 45-85\n False (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\n[1/2] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-7c83247c\n\n[2/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_suggested_edits_issues_view.json b/tests/fixtures/parity/expected/review__get_suggested_edits_issues_view.json new file mode 100644 index 0000000..2f8589c --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_suggested_edits_issues_view.json @@ -0,0 +1,128 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 12 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": { + "edits": [ + { + "end": 29, + "position": 0, + "replacement": "Paris", + "start": 23, + "text": "Berlin" + } + ], + "status": "completed" + }, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "verdict": "False", + "verification_id": "7c83247c", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "verified_claim": null + }, + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 1, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": { + "edits": null, + "status": "pending" + }, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": true, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 15, + "review_id": "d6b2bd72", + "status": "verifying", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 2, + "verifications": { + "completed": 1, + "failed": 0, + "planned": 2 + } + }, + "view": "issues" + }, + "exit_code": 2, + "render": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\n[1/2] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-7c83247c\n\n[2/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_url_review.json b/tests/fixtures/parity/expected/review__get_url_review.json new file mode 100644 index 0000000..ea99aa8 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_url_review.json @@ -0,0 +1,104 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": [ + { + "end": null, + "start": null, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "exit_code": 0, + "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__get_verifying.json b/tests/fixtures/parity/expected/review__get_verifying.json new file mode 100644 index 0000000..0b901c0 --- /dev/null +++ b/tests/fixtures/parity/expected/review__get_verifying.json @@ -0,0 +1,177 @@ +{ + "dump": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "assessment", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": null, + "confidence": null, + "content_status": "available", + "created_at": null, + "depth": null, + "domain": null, + "entities": [], + "executive_summary": null, + "failure": null, + "key_finding": null, + "language": null, + "lenz_score": null, + "modified_at": null, + "status": "processing", + "suggested_rewrite": null, + "task_id": null, + "url": null, + "verdict": null, + "verification_id": null, + "verification_url": null, + "visibility": null, + "warnings": [] + } + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": null, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 15, + "review_id": "d6b2bd72", + "status": "verifying", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 1 + } + }, + "view": "full" + }, + "exit_code": 2, + "render": "Review d6b2bd72: verifying — 2 claims: 1 issue, 1 true or mostly true · 0 of 1 deep-checked · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n\n[2/2] Water boils at 100 C at sea level.\n True (high) · quick check\n", + "render_issues": "Review d6b2bd72: verifying — 2 claims: 1 issue, 1 true or mostly true · 0 of 1 deep-checked · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n", + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__idempotency_body_mismatch_422.json b/tests/fixtures/parity/expected/review__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..5de20e3 --- /dev/null +++ b/tests/fixtures/parity/expected/review__idempotency_body_mismatch_422.json @@ -0,0 +1,29 @@ +{ + "error": { + "cause": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "header" + ], + "msg": "Idempotency-Key reused with a different request body." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Idempotency-Key reused with a different request body.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__idempotency_conflict_409.json b/tests/fixtures/parity/expected/review__idempotency_conflict_409.json new file mode 100644 index 0000000..6f3c206 --- /dev/null +++ b/tests/fixtures/parity/expected/review__idempotency_conflict_409.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "A review with this Idempotency-Key is still being created. Retry shortly.", + "code": "idempotency_conflict", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "A review with this Idempotency-Key is still being created. Retry shortly.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "A review with this Idempotency-Key is still being created. Retry shortly.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "A review with this Idempotency-Key is still being created. Retry shortly.", + "status": 409 + } + }, + "request_id": "", + "status_code": 409, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/review__idempotency_conflict_409_existing_review.json b/tests/fixtures/parity/expected/review__idempotency_conflict_409_existing_review.json new file mode 100644 index 0000000..6f3c206 --- /dev/null +++ b/tests/fixtures/parity/expected/review__idempotency_conflict_409_existing_review.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "A review with this Idempotency-Key is still being created. Retry shortly.", + "code": "idempotency_conflict", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "A review with this Idempotency-Key is still being created. Retry shortly.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "A review with this Idempotency-Key is still being created. Retry shortly.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "A review with this Idempotency-Key is still being created. Retry shortly.", + "status": 409 + } + }, + "request_id": "", + "status_code": 409, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/review__idempotent_replay_202.json b/tests/fixtures/parity/expected/review__idempotent_replay_202.json new file mode 100644 index 0000000..17e07a5 --- /dev/null +++ b/tests/fixtures/parity/expected/review__idempotent_replay_202.json @@ -0,0 +1,7 @@ +{ + "dump": { + "review_id": "d6b2bd72", + "status": "queued" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__receipt_202.json b/tests/fixtures/parity/expected/review__receipt_202.json new file mode 100644 index 0000000..17e07a5 --- /dev/null +++ b/tests/fixtures/parity/expected/review__receipt_202.json @@ -0,0 +1,7 @@ +{ + "dump": { + "review_id": "d6b2bd72", + "status": "queued" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/expected/review__receipt_202_empty_webhook_url.json new file mode 100644 index 0000000..17e07a5 --- /dev/null +++ b/tests/fixtures/parity/expected/review__receipt_202_empty_webhook_url.json @@ -0,0 +1,7 @@ +{ + "dump": { + "review_id": "d6b2bd72", + "status": "queued" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__receipt_202_webhook_url.json b/tests/fixtures/parity/expected/review__receipt_202_webhook_url.json new file mode 100644 index 0000000..17e07a5 --- /dev/null +++ b/tests/fixtures/parity/expected/review__receipt_202_webhook_url.json @@ -0,0 +1,7 @@ +{ + "dump": { + "review_id": "d6b2bd72", + "status": "queued" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/review__replay_later_202.json b/tests/fixtures/parity/expected/review__replay_later_202.json new file mode 100644 index 0000000..17e07a5 --- /dev/null +++ b/tests/fixtures/parity/expected/review__replay_later_202.json @@ -0,0 +1,7 @@ +{ + "dump": { + "review_id": "d6b2bd72", + "status": "queued" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__batch_202.json b/tests/fixtures/parity/expected/verify__batch_202.json new file mode 100644 index 0000000..d044b7c --- /dev/null +++ b/tests/fixtures/parity/expected/verify__batch_202.json @@ -0,0 +1,16 @@ +{ + "dump": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "claim_text": "The Earth is round.", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be" + }, + { + "claim_text": "Water boils at 100C at sea level.", + "task_id": "13610f0b64b63e006dc66364e0e82c85" + } + ] + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__batch_capacity_503.json b/tests/fixtures/parity/expected/verify__batch_capacity_503.json new file mode 100644 index 0000000..11cc917 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__batch_capacity_503.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "status": 503 + } + }, + "request_id": "", + "retry_after": null, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/verify__batch_empty_422.json b/tests/fixtures/parity/expected/verify__batch_empty_422.json new file mode 100644 index 0000000..e1ddac5 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__batch_empty_422.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "claims is required and must be non-empty.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "claims is required and must be non-empty.\n Fix: Check the request body against the OpenAPI spec.", + "message": "claims is required and must be non-empty.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "claims is required and must be non-empty.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__batch_idempotency_conflict_409.json b/tests/fixtures/parity/expected/verify__batch_idempotency_conflict_409.json new file mode 100644 index 0000000..54ca3d5 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__batch_idempotency_conflict_409.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "A request with this Idempotency-Key is already in progress.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "A request with this Idempotency-Key is already in progress.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "A request with this Idempotency-Key is already in progress.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "A request with this Idempotency-Key is already in progress.", + "status": 409 + } + }, + "request_id": "", + "status_code": 409, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__batch_item_missing_claim_422.json b/tests/fixtures/parity/expected/verify__batch_item_missing_claim_422.json new file mode 100644 index 0000000..f2a3fe8 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__batch_item_missing_claim_422.json @@ -0,0 +1,34 @@ +{ + "error": { + "cause": "[{'type': 'missing', 'loc': ['body', 'payload', 'claims', 1, 'text'], 'msg': 'Field required'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "claims", + 1, + "text" + ], + "msg": "Field required", + "type": "missing" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'missing', 'loc': ['body', 'payload', 'claims', 1, 'text'], 'msg': 'Field required'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'claims', 1, 'text'], 'msg': 'Field required'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'claims', 1, 'text'], 'msg': 'Field required'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__batch_no_credits_402.json b/tests/fixtures/parity/expected/verify__batch_no_credits_402.json new file mode 100644 index 0000000..806620a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__batch_no_credits_402.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "Insufficient credits for batch.", + "code": "no_credits", + "cost": 10, + "credit_balance": 0, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "Insufficient credits for batch.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "Insufficient credits for batch.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "Insufficient credits for batch.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 0, + "request_id": "", + "requested": 1, + "resets_at": "2026-10-01T09:14:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/verify__batch_partial_202.json b/tests/fixtures/parity/expected/verify__batch_partial_202.json new file mode 100644 index 0000000..96fb74b --- /dev/null +++ b/tests/fixtures/parity/expected/verify__batch_partial_202.json @@ -0,0 +1,13 @@ +{ + "dump": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "claim_text": "First claim.", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be" + } + ], + "partial": true + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__batch_too_many_422.json b/tests/fixtures/parity/expected/verify__batch_too_many_422.json new file mode 100644 index 0000000..c07dafe --- /dev/null +++ b/tests/fixtures/parity/expected/verify__batch_too_many_422.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Batch size exceeds maximum of 20.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Batch size exceeds maximum of 20.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Batch size exceeds maximum of 20.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Batch size exceeds maximum of 20.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__blank_claim_422.json b/tests/fixtures/parity/expected/verify__blank_claim_422.json new file mode 100644 index 0000000..872ff11 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__blank_claim_422.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Text is required.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Text is required.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Text is required.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Text is required.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__capacity_503.json b/tests/fixtures/parity/expected/verify__capacity_503.json new file mode 100644 index 0000000..11cc917 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__capacity_503.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "doc_url": "https://lenz.io/docs/errors#unavailable", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "status": 503 + } + }, + "request_id": "", + "retry_after": null, + "status_code": 503, + "type": "LenzUpstreamUnavailableError" + } +} diff --git a/tests/fixtures/parity/expected/verify__idempotency_body_mismatch_422.json b/tests/fixtures/parity/expected/verify__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..989af48 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__idempotency_body_mismatch_422.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Idempotency-Key reused with a different request body.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Idempotency-Key reused with a different request body.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Idempotency-Key reused with a different request body.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__idempotency_conflict_409.json b/tests/fixtures/parity/expected/verify__idempotency_conflict_409.json new file mode 100644 index 0000000..54ca3d5 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__idempotency_conflict_409.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "A request with this Idempotency-Key is already in progress.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "A request with this Idempotency-Key is already in progress.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "A request with this Idempotency-Key is already in progress.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "A request with this Idempotency-Key is already in progress.", + "status": 409 + } + }, + "request_id": "", + "status_code": 409, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__idempotency_key_replay.json b/tests/fixtures/parity/expected/verify__idempotency_key_replay.json new file mode 100644 index 0000000..4aa7f3a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__idempotency_key_replay.json @@ -0,0 +1,9 @@ +{ + "dump": { + "chain_id": "78ac4e9f234ea3bd", + "claim_text": "", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__implicit_dedup_200.json b/tests/fixtures/parity/expected/verify__implicit_dedup_200.json new file mode 100644 index 0000000..77b6440 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__implicit_dedup_200.json @@ -0,0 +1,8 @@ +{ + "dump": { + "claim_text": "", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__implicit_repeat_replay.json b/tests/fixtures/parity/expected/verify__implicit_repeat_replay.json new file mode 100644 index 0000000..4aa7f3a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__implicit_repeat_replay.json @@ -0,0 +1,9 @@ +{ + "dump": { + "chain_id": "78ac4e9f234ea3bd", + "claim_text": "", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__invalid_depth_422.json b/tests/fixtures/parity/expected/verify__invalid_depth_422.json new file mode 100644 index 0000000..128dad2 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__invalid_depth_422.json @@ -0,0 +1,35 @@ +{ + "error": { + "cause": "[{'type': 'literal_error', 'loc': ['body', 'payload', 'depth'], 'msg': \"Input should be 'standard' or 'low'\", 'ctx': {'expected': \"'standard' or 'low'\"}}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "ctx": { + "expected": "'standard' or 'low'" + }, + "loc": [ + "body", + "payload", + "depth" + ], + "msg": "Input should be 'standard' or 'low'", + "type": "literal_error" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'literal_error', 'loc': ['body', 'payload', 'depth'], 'msg': \"Input should be 'standard' or 'low'\", 'ctx': {'expected': \"'standard' or 'low'\"}}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'literal_error', 'loc': ['body', 'payload', 'depth'], 'msg': \"Input should be 'standard' or 'low'\", 'ctx': {'expected': \"'standard' or 'low'\"}}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'literal_error', 'loc': ['body', 'payload', 'depth'], 'msg': \"Input should be 'standard' or 'low'\", 'ctx': {'expected': \"'standard' or 'low'\"}}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__invalid_language_422.json b/tests/fixtures/parity/expected/verify__invalid_language_422.json new file mode 100644 index 0000000..b5218f2 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__invalid_language_422.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Unsupported language 'xx-not-a-language'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Unsupported language 'xx-not-a-language'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Unsupported language 'xx-not-a-language'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Unsupported language 'xx-not-a-language'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__list_200.json b/tests/fixtures/parity/expected/verify__list_200.json new file mode 100644 index 0000000..9b7f3a5 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__list_200.json @@ -0,0 +1,40 @@ +{ + "dump": { + "items": [ + { + "claim": "The Earth is round.", + "confidence": "high", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + }, + { + "claim": "The Earth is round.", + "confidence": "high", + "created_at": "2026-10-01T09:28:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "7c83247c" + } + ], + "page": 1, + "page_size": 20, + "total": 2 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__list_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/verify__list_200_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..8550130 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__list_200_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,25 @@ +{ + "dump": { + "items": [ + { + "claim": "The Earth is round.", + "confidence": "high", + "created_at": "2026-10-01T23:55:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + } + ], + "page": 1, + "page_size": 20, + "total": 1 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__list_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/verify__list_200_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..b333318 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__list_200_modified_at_same_day_hours_apart.json @@ -0,0 +1,25 @@ +{ + "dump": { + "items": [ + { + "claim": "The Earth is round.", + "confidence": "high", + "created_at": "2026-10-01T08:00:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + } + ], + "page": 1, + "page_size": 20, + "total": 1 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__list_clamped_200.json b/tests/fixtures/parity/expected/verify__list_clamped_200.json new file mode 100644 index 0000000..b48e6be --- /dev/null +++ b/tests/fixtures/parity/expected/verify__list_clamped_200.json @@ -0,0 +1,9 @@ +{ + "dump": { + "items": [], + "page": 1, + "page_size": 100, + "total": 0 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__list_empty_200.json b/tests/fixtures/parity/expected/verify__list_empty_200.json new file mode 100644 index 0000000..d628806 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__list_empty_200.json @@ -0,0 +1,9 @@ +{ + "dump": { + "items": [], + "page": 1, + "page_size": 20, + "total": 0 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__list_page2_200.json b/tests/fixtures/parity/expected/verify__list_page2_200.json new file mode 100644 index 0000000..c5aab9a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__list_page2_200.json @@ -0,0 +1,25 @@ +{ + "dump": { + "items": [ + { + "claim": "The Earth is round.", + "confidence": "high", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + } + ], + "page": 2, + "page_size": 2, + "total": 3 + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__misnamed_field_422.json b/tests/fixtures/parity/expected/verify__misnamed_field_422.json new file mode 100644 index 0000000..6760d1a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__misnamed_field_422.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__missing_claim_422.json b/tests/fixtures/parity/expected/verify__missing_claim_422.json new file mode 100644 index 0000000..6760d1a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__missing_claim_422.json @@ -0,0 +1,32 @@ +{ + "error": { + "cause": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required", + "type": "missing" + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]\n Fix: Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "[{'type': 'missing', 'loc': ['body', 'payload', 'text'], 'msg': 'Field required'}]", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__no_credits_402.json b/tests/fixtures/parity/expected/verify__no_credits_402.json new file mode 100644 index 0000000..f3a12a3 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__no_credits_402.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "No remaining claim checks.", + "code": "no_credits", + "cost": 10, + "credit_balance": 0, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "No remaining claim checks.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "No remaining claim checks.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "No remaining claim checks.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 0, + "request_id": "", + "requested": null, + "resets_at": "2026-10-01T09:14:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/verify__replay_later_202.json b/tests/fixtures/parity/expected/verify__replay_later_202.json new file mode 100644 index 0000000..4aa7f3a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__replay_later_202.json @@ -0,0 +1,9 @@ +{ + "dump": { + "chain_id": "78ac4e9f234ea3bd", + "claim_text": "", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__select_202.json b/tests/fixtures/parity/expected/verify__select_202.json new file mode 100644 index 0000000..d044b7c --- /dev/null +++ b/tests/fixtures/parity/expected/verify__select_202.json @@ -0,0 +1,16 @@ +{ + "dump": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "claim_text": "The Earth is round.", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be" + }, + { + "claim_text": "Water boils at 100C at sea level.", + "task_id": "13610f0b64b63e006dc66364e0e82c85" + } + ] + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__select_empty_422.json b/tests/fixtures/parity/expected/verify__select_empty_422.json new file mode 100644 index 0000000..975cb65 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__select_empty_422.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "texts is required and must be non-empty.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "texts is required and must be non-empty.\n Fix: Check the request body against the OpenAPI spec.", + "message": "texts is required and must be non-empty.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "texts is required and must be non-empty.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__select_invalid_selection_422.json b/tests/fixtures/parity/expected/verify__select_invalid_selection_422.json new file mode 100644 index 0000000..1a020a2 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__select_invalid_selection_422.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Selected text was not one of the offered claims: 'The Moon is made of cheese.'", + "code": "invalid_selection", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Selected text was not one of the offered claims: 'The Moon is made of cheese.'\n Fix: Check the request body against the OpenAPI spec.", + "message": "Selected text was not one of the offered claims: 'The Moon is made of cheese.'", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Selected text was not one of the offered claims: 'The Moon is made of cheese.'", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__select_no_selection_pending_409.json b/tests/fixtures/parity/expected/verify__select_no_selection_pending_409.json new file mode 100644 index 0000000..fd4d147 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__select_no_selection_pending_409.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "This task has no pending claim selection.", + "code": "no_selection_pending", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "This task has no pending claim selection.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "This task has no pending claim selection.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "This task has no pending claim selection.", + "status": 409 + } + }, + "request_id": "", + "status_code": 409, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__select_too_many_422.json b/tests/fixtures/parity/expected/verify__select_too_many_422.json new file mode 100644 index 0000000..9a93a10 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__select_too_many_422.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "Cannot select more than 20 claims.", + "code": "", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "Cannot select more than 20 claims.\n Fix: Check the request body against the OpenAPI spec.", + "message": "Cannot select more than 20 claims.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "Cannot select more than 20 claims.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/verify__select_unknown_task_404.json b/tests/fixtures/parity/expected/verify__select_unknown_task_404.json new file mode 100644 index 0000000..68a468c --- /dev/null +++ b/tests/fixtures/parity/expected/verify__select_unknown_task_404.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Task not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Task not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Task not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Task not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_cancelled_after_a_while.json b/tests/fixtures/parity/expected/verify__status_cancelled_after_a_while.json new file mode 100644 index 0000000..0c51d3c --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_cancelled_after_a_while.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "https://lenz.io/docs/errors#cancelled", + "error": "Cancelled.", + "failure_class": "cancelled", + "failure_detail": "", + "failure_reason": "cancelled", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": null, + "retryable": false, + "similar_claims": [], + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "failed — Cancelled.\n", + "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Cancelled.\",\n \"failure_reason\": \"cancelled\",\n \"failure_detail\": \"\",\n \"failure_class\": \"cancelled\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#cancelled\"\n}\n", + "wait": { + "cause": "Cancelled.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "cancelled", + "failure_reason": "cancelled", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "friendly_text": "Pipeline failed: Cancelled.\n Fix: Retry with a different claim, or check status.error for the diagnostic.", + "hint": "", + "message": "Pipeline failed: Cancelled.", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "message": "Pipeline failed: Cancelled.", + "status": 0 + } + }, + "request_id": "", + "retryable": false, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_completed.json b/tests/fixtures/parity/expected/verify__status_completed.json new file mode 100644 index 0000000..4455d97 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_completed.json @@ -0,0 +1,203 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "retryable": null, + "similar_claims": [], + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:21:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "wait": { + "returned": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + } + } +} diff --git a/tests/fixtures/parity/expected/verify__status_completed_after_a_while.json b/tests/fixtures/parity/expected/verify__status_completed_after_a_while.json new file mode 100644 index 0000000..4455d97 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_completed_after_a_while.json @@ -0,0 +1,203 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "retryable": null, + "similar_claims": [], + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:21:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "wait": { + "returned": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + } + } +} diff --git a/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..3b77489 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,203 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "retryable": null, + "similar_claims": [], + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "wait": { + "returned": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + } + } +} diff --git a/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..29f1593 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json @@ -0,0 +1,203 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "retryable": null, + "similar_claims": [], + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T08:00:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "wait": { + "returned": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + } + } +} diff --git a/tests/fixtures/parity/expected/verify__status_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/verify__status_completed_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..3b77489 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_completed_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,203 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "retryable": null, + "similar_claims": [], + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "wait": { + "returned": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + } + } +} diff --git a/tests/fixtures/parity/expected/verify__status_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/verify__status_completed_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..29f1593 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_completed_modified_at_same_day_hours_apart.json @@ -0,0 +1,203 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "retryable": null, + "similar_claims": [], + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T08:00:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "wait": { + "returned": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + } + } +} diff --git a/tests/fixtures/parity/expected/verify__status_failed.json b/tests/fixtures/parity/expected/verify__status_failed.json new file mode 100644 index 0000000..c379a8d --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_failed.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence", + "error": "Pipeline stopped at: research_empty", + "failure_class": "insufficient_evidence", + "failure_detail": "", + "failure_reason": "research_empty", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": null, + "retryable": false, + "similar_claims": [], + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "failed — Pipeline stopped at: research_empty\n", + "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped at: research_empty\",\n \"failure_reason\": \"research_empty\",\n \"failure_detail\": \"\",\n \"failure_class\": \"insufficient_evidence\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#insufficient-evidence\"\n}\n", + "wait": { + "cause": "Pipeline stopped at: research_empty", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "friendly_text": "Pipeline failed: Pipeline stopped at: research_empty\n Fix: Retry with a different claim, or check status.error for the diagnostic.", + "hint": "", + "message": "Pipeline failed: Pipeline stopped at: research_empty", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "message": "Pipeline failed: Pipeline stopped at: research_empty", + "status": 0 + } + }, + "request_id": "", + "retryable": false, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_failed_after_a_while.json b/tests/fixtures/parity/expected/verify__status_failed_after_a_while.json new file mode 100644 index 0000000..1de2af6 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_failed_after_a_while.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "https://lenz.io/docs/errors#internal", + "error": "Pipeline stopped: conclusion_failed.", + "failure_class": "internal", + "failure_detail": "", + "failure_reason": "conclusion_failed", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": null, + "retryable": false, + "similar_claims": [], + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "failed — Pipeline stopped: conclusion_failed.\n", + "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped: conclusion_failed.\",\n \"failure_reason\": \"conclusion_failed\",\n \"failure_detail\": \"\",\n \"failure_class\": \"internal\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#internal\"\n}\n", + "wait": { + "cause": "Pipeline stopped: conclusion_failed.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "internal", + "failure_reason": "conclusion_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "friendly_text": "Pipeline failed: Pipeline stopped: conclusion_failed.\n Fix: Retry with a different claim, or check status.error for the diagnostic.", + "hint": "", + "message": "Pipeline failed: Pipeline stopped: conclusion_failed.", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "message": "Pipeline failed: Pipeline stopped: conclusion_failed.", + "status": 0 + } + }, + "request_id": "", + "retryable": false, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_failed_after_a_while_framing.json b/tests/fixtures/parity/expected/verify__status_failed_after_a_while_framing.json new file mode 100644 index 0000000..52d9c84 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_failed_after_a_while_framing.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "error": "Pipeline stopped: framing_failed.", + "failure_class": "upstream_unavailable", + "failure_detail": "", + "failure_reason": "framing_failed", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": null, + "retryable": true, + "similar_claims": [], + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "failed — Pipeline stopped: framing_failed.\n", + "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped: framing_failed.\",\n \"failure_reason\": \"framing_failed\",\n \"failure_detail\": \"\",\n \"failure_class\": \"upstream_unavailable\",\n \"retryable\": true,\n \"docs_url\": \"https://lenz.io/docs/errors#upstream-unavailable\"\n}\n", + "wait": { + "cause": "Pipeline stopped: framing_failed.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "upstream_unavailable", + "failure_reason": "framing_failed", + "fix": "Transient provider outage — retry the same request after a short wait.", + "friendly_text": "Pipeline failed: Pipeline stopped: framing_failed.\n Fix: Transient provider outage — retry the same request after a short wait.", + "hint": "", + "message": "Pipeline failed: Pipeline stopped: framing_failed.", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Transient provider outage — retry the same request after a short wait.", + "message": "Pipeline failed: Pipeline stopped: framing_failed.", + "status": 0 + } + }, + "request_id": "", + "retryable": true, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_failed_retryable.json b/tests/fixtures/parity/expected/verify__status_failed_retryable.json new file mode 100644 index 0000000..fbe1bf9 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_failed_retryable.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "error": "Pipeline stopped at: adjudication_failed", + "failure_class": "upstream_unavailable", + "failure_detail": "", + "failure_reason": "adjudication_failed", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": null, + "retryable": true, + "similar_claims": [], + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "failed — Pipeline stopped at: adjudication_failed\n", + "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped at: adjudication_failed\",\n \"failure_reason\": \"adjudication_failed\",\n \"failure_detail\": \"\",\n \"failure_class\": \"upstream_unavailable\",\n \"retryable\": true,\n \"docs_url\": \"https://lenz.io/docs/errors#upstream-unavailable\"\n}\n", + "wait": { + "cause": "Pipeline stopped at: adjudication_failed", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "upstream_unavailable", + "failure_reason": "adjudication_failed", + "fix": "Transient provider outage — retry the same request after a short wait.", + "friendly_text": "Pipeline failed: Pipeline stopped at: adjudication_failed\n Fix: Transient provider outage — retry the same request after a short wait.", + "hint": "", + "message": "Pipeline failed: Pipeline stopped at: adjudication_failed", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Transient provider outage — retry the same request after a short wait.", + "message": "Pipeline failed: Pipeline stopped at: adjudication_failed", + "status": 0 + } + }, + "request_id": "", + "retryable": true, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_needs_input.json b/tests/fixtures/parity/expected/verify__status_needs_input.json new file mode 100644 index 0000000..13a266b --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_needs_input.json @@ -0,0 +1,90 @@ +{ + "dump": { + "candidates": [], + "claims": [ + { + "domain": "Science", + "text": "The Earth is round." + }, + { + "domain": "Science", + "text": "Water boils at 100C at sea level." + } + ], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "multi_claim", + "result": null, + "retryable": null, + "similar_claims": [], + "status": "needs_input", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "needs input (multi_claim)\nclaims found:\n 1. The Earth is round.\n 2. Water boils at 100C at sea level.\nresolve it: lenz verify --resume t --claim --detach\n", + "render_json": "{\n \"status\": \"needs_input\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"multi_claim\",\n \"hint\": \"The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [\n {\n \"text\": \"The Earth is round.\",\n \"domain\": \"Science\"\n },\n {\n \"text\": \"Water boils at 100C at sea level.\",\n \"domain\": \"Science\"\n }\n ],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "wait": { + "cause": "The verification needs caller input to proceed.", + "code": "", + "doc_url": "https://lenz.io/docs/verify#needs-input", + "fix": "Inspect the payload, then call client.select(task_id, texts=[...]) with the chosen claim(s).", + "friendly_text": "Pipeline paused: multi_claim\n Fix: Inspect the payload, then call client.select(task_id, texts=[...]) with the chosen claim(s).", + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.", + "kind": "multi_claim", + "message": "Pipeline paused: multi_claim", + "payload": { + "candidates": [], + "claims": [ + { + "domain": "Science", + "text": "The Earth is round." + }, + { + "domain": "Science", + "text": "Water boils at 100C at sea level." + } + ], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "multi_claim", + "result": null, + "retryable": null, + "similar_claims": [], + "status": "needs_input", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "payload_json": { + "error": { + "code": "needs_input", + "fix": "Inspect the payload, then call client.select(task_id, texts=[...]) with the chosen claim(s).", + "message": "Pipeline paused: multi_claim", + "status": 0 + } + }, + "request_id": "", + "status_code": 0, + "task_id": "t", + "type": "LenzNeedsInputError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_not_a_claim.json b/tests/fixtures/parity/expected/verify__status_not_a_claim.json new file mode 100644 index 0000000..5f7f1c5 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_not_a_claim.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "error": "Not a verifiable claim.", + "failure_class": "invalid_input", + "failure_detail": "", + "failure_reason": "not_a_claim", + "hint": "The input is a greeting, not a statement that can be checked. Send one factual claim, or run the text through /extract to enumerate its claims.", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": null, + "retryable": false, + "similar_claims": [], + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "failed — Not a verifiable claim.\n", + "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"The input is a greeting, not a statement that can be checked. Send one factual claim, or run the text through /extract to enumerate its claims.\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Not a verifiable claim.\",\n \"failure_reason\": \"not_a_claim\",\n \"failure_detail\": \"\",\n \"failure_class\": \"invalid_input\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#invalid-input\"\n}\n", + "wait": { + "cause": "Not a verifiable claim.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "invalid_input", + "failure_reason": "not_a_claim", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "friendly_text": "Pipeline failed: Not a verifiable claim.\n Fix: Retry with a different claim, or check status.error for the diagnostic.", + "hint": "The input is a greeting, not a statement that can be checked. Send one factual claim, or run the text through /extract to enumerate its claims.", + "message": "Pipeline failed: Not a verifiable claim.", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "message": "Pipeline failed: Not a verifiable claim.", + "status": 0 + } + }, + "request_id": "", + "retryable": false, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_not_a_claim_after_a_while.json b/tests/fixtures/parity/expected/verify__status_not_a_claim_after_a_while.json new file mode 100644 index 0000000..422b2c4 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_not_a_claim_after_a_while.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "error": "Pipeline stopped: not_a_claim.", + "failure_class": "invalid_input", + "failure_detail": "", + "failure_reason": "not_a_claim", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": null, + "retryable": false, + "similar_claims": [], + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "failed — Pipeline stopped: not_a_claim.\n", + "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped: not_a_claim.\",\n \"failure_reason\": \"not_a_claim\",\n \"failure_detail\": \"\",\n \"failure_class\": \"invalid_input\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#invalid-input\"\n}\n", + "wait": { + "cause": "Pipeline stopped: not_a_claim.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "invalid_input", + "failure_reason": "not_a_claim", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "friendly_text": "Pipeline failed: Pipeline stopped: not_a_claim.\n Fix: Retry with a different claim, or check status.error for the diagnostic.", + "hint": "", + "message": "Pipeline failed: Pipeline stopped: not_a_claim.", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "message": "Pipeline failed: Pipeline stopped: not_a_claim.", + "status": 0 + } + }, + "request_id": "", + "retryable": false, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_not_yours_404.json b/tests/fixtures/parity/expected/verify__status_not_yours_404.json new file mode 100644 index 0000000..68a468c --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_not_yours_404.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Task not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Task not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Task not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Task not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_older_run_completed.json b/tests/fixtures/parity/expected/verify__status_older_run_completed.json new file mode 100644 index 0000000..4455d97 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_older_run_completed.json @@ -0,0 +1,203 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "retryable": null, + "similar_claims": [], + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:21:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "wait": { + "returned": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + } + } +} diff --git a/tests/fixtures/parity/expected/verify__status_older_run_failed_crashed.json b/tests/fixtures/parity/expected/verify__status_older_run_failed_crashed.json new file mode 100644 index 0000000..6700b6d --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_older_run_failed_crashed.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "https://lenz.io/docs/errors#internal", + "error": "Pipeline failed.", + "failure_class": "internal", + "failure_detail": "", + "failure_reason": "task_error", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": null, + "retryable": false, + "similar_claims": [], + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "failed — Pipeline failed.\n", + "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline failed.\",\n \"failure_reason\": \"task_error\",\n \"failure_detail\": \"\",\n \"failure_class\": \"internal\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#internal\"\n}\n", + "wait": { + "cause": "Pipeline failed.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "internal", + "failure_reason": "task_error", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "friendly_text": "Pipeline failed: Pipeline failed.\n Fix: Retry with a different claim, or check status.error for the diagnostic.", + "hint": "", + "message": "Pipeline failed: Pipeline failed.", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "message": "Pipeline failed: Pipeline failed.", + "status": 0 + } + }, + "request_id": "", + "retryable": false, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_older_run_failed_insufficient_evidence.json b/tests/fixtures/parity/expected/verify__status_older_run_failed_insufficient_evidence.json new file mode 100644 index 0000000..c379a8d --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_older_run_failed_insufficient_evidence.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence", + "error": "Pipeline stopped at: research_empty", + "failure_class": "insufficient_evidence", + "failure_detail": "", + "failure_reason": "research_empty", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": null, + "retryable": false, + "similar_claims": [], + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "failed — Pipeline stopped at: research_empty\n", + "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped at: research_empty\",\n \"failure_reason\": \"research_empty\",\n \"failure_detail\": \"\",\n \"failure_class\": \"insufficient_evidence\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#insufficient-evidence\"\n}\n", + "wait": { + "cause": "Pipeline stopped at: research_empty", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "friendly_text": "Pipeline failed: Pipeline stopped at: research_empty\n Fix: Retry with a different claim, or check status.error for the diagnostic.", + "hint": "", + "message": "Pipeline failed: Pipeline stopped at: research_empty", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "message": "Pipeline failed: Pipeline stopped at: research_empty", + "status": 0 + } + }, + "request_id": "", + "retryable": false, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_older_run_in_progress.json b/tests/fixtures/parity/expected/verify__status_older_run_in_progress.json new file mode 100644 index 0000000..fb3142e --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_older_run_in_progress.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "", + "progress": { + "elapsed_seconds": 2, + "index": 2, + "poll_after_seconds": 5, + "step": "research", + "total": 5 + }, + "reason": "", + "result": null, + "retryable": null, + "similar_claims": [], + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "processing — Gathering evidence (2/5)\n", + "render_json": "{\n \"status\": \"processing\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"research\",\n \"index\": 2,\n \"total\": 5,\n \"elapsed_seconds\": 2,\n \"poll_after_seconds\": 5\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "wait": { + "cause": "unknown", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "", + "failure_reason": "", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "friendly_text": "Pipeline failed: unknown\n Fix: Retry with a different claim, or check status.error for the diagnostic.", + "hint": "", + "message": "Pipeline failed: unknown", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "message": "Pipeline failed: unknown", + "status": 0 + } + }, + "request_id": "", + "retryable": null, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_processing.json b/tests/fixtures/parity/expected/verify__status_processing.json new file mode 100644 index 0000000..fb3142e --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_processing.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "", + "progress": { + "elapsed_seconds": 2, + "index": 2, + "poll_after_seconds": 5, + "step": "research", + "total": 5 + }, + "reason": "", + "result": null, + "retryable": null, + "similar_claims": [], + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "processing — Gathering evidence (2/5)\n", + "render_json": "{\n \"status\": \"processing\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"research\",\n \"index\": 2,\n \"total\": 5,\n \"elapsed_seconds\": 2,\n \"poll_after_seconds\": 5\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "wait": { + "cause": "unknown", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "", + "failure_reason": "", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "friendly_text": "Pipeline failed: unknown\n Fix: Retry with a different claim, or check status.error for the diagnostic.", + "hint": "", + "message": "Pipeline failed: unknown", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "message": "Pipeline failed: unknown", + "status": 0 + } + }, + "request_id": "", + "retryable": null, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_processing_after_a_while.json b/tests/fixtures/parity/expected/verify__status_processing_after_a_while.json new file mode 100644 index 0000000..e7bb01d --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_processing_after_a_while.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "", + "error": "", + "failure_class": "", + "failure_detail": "", + "failure_reason": "", + "hint": "", + "progress": { + "elapsed_seconds": 2, + "index": 4, + "poll_after_seconds": 5, + "step": "adjudication", + "total": 5 + }, + "reason": "", + "result": null, + "retryable": null, + "similar_claims": [], + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "processing — Panel review across models (4/5)\n", + "render_json": "{\n \"status\": \"processing\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"adjudication\",\n \"index\": 4,\n \"total\": 5,\n \"elapsed_seconds\": 2,\n \"poll_after_seconds\": 5\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "wait": { + "cause": "unknown", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "", + "failure_reason": "", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "friendly_text": "Pipeline failed: unknown\n Fix: Retry with a different claim, or check status.error for the diagnostic.", + "hint": "", + "message": "Pipeline failed: unknown", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Retry with a different claim, or check status.error for the diagnostic.", + "message": "Pipeline failed: unknown", + "status": 0 + } + }, + "request_id": "", + "retryable": null, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_task_stuck.json b/tests/fixtures/parity/expected/verify__status_task_stuck.json new file mode 100644 index 0000000..d7e9b4b --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_task_stuck.json @@ -0,0 +1,51 @@ +{ + "dump": { + "candidates": [], + "claims": [], + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "error": "The task was never completed and has been marked failed.", + "failure_class": "upstream_unavailable", + "failure_detail": "", + "failure_reason": "task_stuck", + "hint": "", + "progress": { + "elapsed_seconds": null, + "index": null, + "poll_after_seconds": null, + "step": "", + "total": null + }, + "reason": "", + "result": null, + "retryable": true, + "similar_claims": [], + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "failed — The task was never completed and has been marked failed.\n", + "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"The task was never completed and has been marked failed.\",\n \"failure_reason\": \"task_stuck\",\n \"failure_detail\": \"\",\n \"failure_class\": \"upstream_unavailable\",\n \"retryable\": true,\n \"docs_url\": \"https://lenz.io/docs/errors#upstream-unavailable\"\n}\n", + "wait": { + "cause": "The task was never completed and has been marked failed.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "failure_class": "upstream_unavailable", + "failure_reason": "task_stuck", + "fix": "Transient provider outage — retry the same request after a short wait.", + "friendly_text": "Pipeline failed: The task was never completed and has been marked failed.\n Fix: Transient provider outage — retry the same request after a short wait.", + "hint": "", + "message": "Pipeline failed: The task was never completed and has been marked failed.", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Transient provider outage — retry the same request after a short wait.", + "message": "Pipeline failed: The task was never completed and has been marked failed.", + "status": 0 + } + }, + "request_id": "", + "retryable": true, + "status_code": 0, + "task_id": "t", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__status_unknown_404.json b/tests/fixtures/parity/expected/verify__status_unknown_404.json new file mode 100644 index 0000000..68a468c --- /dev/null +++ b/tests/fixtures/parity/expected/verify__status_unknown_404.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Task not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Task not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Task not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Task not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__submit_202.json b/tests/fixtures/parity/expected/verify__submit_202.json new file mode 100644 index 0000000..4aa7f3a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__submit_202.json @@ -0,0 +1,9 @@ +{ + "dump": { + "chain_id": "78ac4e9f234ea3bd", + "claim_text": "", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__submit_202_options.json b/tests/fixtures/parity/expected/verify__submit_202_options.json new file mode 100644 index 0000000..4aa7f3a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__submit_202_options.json @@ -0,0 +1,9 @@ +{ + "dump": { + "chain_id": "78ac4e9f234ea3bd", + "claim_text": "", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__submit_202_text_alias.json b/tests/fixtures/parity/expected/verify__submit_202_text_alias.json new file mode 100644 index 0000000..4aa7f3a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__submit_202_text_alias.json @@ -0,0 +1,9 @@ +{ + "dump": { + "chain_id": "78ac4e9f234ea3bd", + "claim_text": "", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null +} diff --git a/tests/fixtures/parity/expected/verify__unauthenticated_401.json b/tests/fixtures/parity/expected/verify__unauthenticated_401.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__unauthenticated_401.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/verify__verification_200.json b/tests/fixtures/parity/expected/verify__verification_200.json new file mode 100644 index 0000000..9c9202f --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_200.json @@ -0,0 +1,92 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_200_covered.json b/tests/fixtures/parity/expected/verify__verification_200_covered.json new file mode 100644 index 0000000..9e542b8 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_200_covered.json @@ -0,0 +1,90 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": "2026-03-10T12:01:30+00:00", + "cap": 10000, + "certificate_id": "def7232d27eda03cf261569aee9948c5", + "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "currency": "EUR", + "reasons": [], + "status": "covered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"covered\",\n \"reasons\": [],\n \"certificate_id\": \"def7232d27eda03cf261569aee9948c5\",\n \"certificate_url\": \"https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5\",\n \"as_of\": \"2026-03-10T12:01:30+00:00\",\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/verify__verification_200_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..fc049f4 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_200_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,92 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_200_modified_at_null.json b/tests/fixtures/parity/expected/verify__verification_200_modified_at_null.json new file mode 100644 index 0000000..9c9202f --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_200_modified_at_null.json @@ -0,0 +1,92 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/verify__verification_200_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..11aaf1c --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_200_modified_at_same_day_hours_apart.json @@ -0,0 +1,92 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T08:00:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_200_modified_at_set.json b/tests/fixtures/parity/expected/verify__verification_200_modified_at_set.json new file mode 100644 index 0000000..fc049f4 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_200_modified_at_set.json @@ -0,0 +1,92 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_200_result_json_conclusion_only.json b/tests/fixtures/parity/expected/verify__verification_200_result_json_conclusion_only.json new file mode 100644 index 0000000..7df6e17 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_200_result_json_conclusion_only.json @@ -0,0 +1,53 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "", + "assessments": [], + "debate_con": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "debate_pro": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "panel_agreement": "split" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "", + "sources": [], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\n── Panel ──\nagreement: split\n\nDebate\n PRO \n CON \n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [],\n \"presumed_intent\": \"\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [],\n \"suggested_rewrite\": null,\n \"sources\": [],\n \"audit\": {\n \"adjudication_summary\": \"\",\n \"assessments\": [],\n \"debate_pro\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"debate_con\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"panel_agreement\": \"split\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_200_result_json_empty.json b/tests/fixtures/parity/expected/verify__verification_200_result_json_empty.json new file mode 100644 index 0000000..7df6e17 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_200_result_json_empty.json @@ -0,0 +1,53 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "", + "assessments": [], + "debate_con": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "debate_pro": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "panel_agreement": "split" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "", + "sources": [], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\n── Panel ──\nagreement: split\n\nDebate\n PRO \n CON \n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [],\n \"presumed_intent\": \"\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [],\n \"suggested_rewrite\": null,\n \"sources\": [],\n \"audit\": {\n \"adjudication_summary\": \"\",\n \"assessments\": [],\n \"debate_pro\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"debate_con\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"panel_agreement\": \"split\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_200_result_json_old_shape_strings.json b/tests/fixtures/parity/expected/verify__verification_200_result_json_old_shape_strings.json new file mode 100644 index 0000000..a8398f8 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_200_result_json_old_shape_strings.json @@ -0,0 +1,69 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "", + "assessments": [ + { + "focus_area": "", + "panelist_name": "Reviewer A", + "reasoning": "", + "score": null, + "warnings": [] + } + ], + "debate_con": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "debate_pro": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "panel_agreement": "split" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "", + "sources": [ + { + "date": "", + "snippet": "Old row.", + "source_name": "", + "title": "", + "url": "https://old.example/a" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (1):\n • https://old.example/a\n https://old.example/a\n Old row.\n\n── Panel ──\nagreement: split\n\nReviewer A\n\nDebate\n PRO \n CON \n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (1):\n • https://old.example/a\n https://old.example/a\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [],\n \"presumed_intent\": \"\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"\",\n \"title\": \"\",\n \"url\": \"https://old.example/a\",\n \"snippet\": \"Old row.\",\n \"date\": \"\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"\",\n \"score\": null,\n \"reasoning\": \"\",\n \"warnings\": []\n }\n ],\n \"debate_pro\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"debate_con\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"panel_agreement\": \"split\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_404.json b/tests/fixtures/parity/expected/verify__verification_404.json new file mode 100644 index 0000000..41573fe --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_404.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__verification_by_task_id_200.json b/tests/fixtures/parity/expected/verify__verification_by_task_id_200.json new file mode 100644 index 0000000..9c9202f --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_by_task_id_200.json @@ -0,0 +1,92 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_failed_409.json b/tests/fixtures/parity/expected/verify__verification_failed_409.json new file mode 100644 index 0000000..e938c8a --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_failed_409.json @@ -0,0 +1,26 @@ +{ + "error": { + "cause": "This check failed and has no result.", + "code": "verification_failed", + "doc_url": "https://lenz.io/docs/errors#insufficient-evidence", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "fix": "Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "friendly_text": "This check failed and has no result.\n Fix: Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "hint": "Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "message": "This check failed and has no result.", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "message": "This check failed and has no result.", + "status": 409 + } + }, + "request_id": "", + "retryable": false, + "status_code": 409, + "task_id": "7cff18da2d979d6370e54a160be121ad", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__verification_failed_409_not_a_claim_after_a_while.json b/tests/fixtures/parity/expected/verify__verification_failed_409_not_a_claim_after_a_while.json new file mode 100644 index 0000000..3a9e337 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_failed_409_not_a_claim_after_a_while.json @@ -0,0 +1,26 @@ +{ + "error": { + "cause": "This check failed and has no result.", + "code": "verification_failed", + "doc_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "not_a_claim", + "fix": "Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "friendly_text": "This check failed and has no result.\n Fix: Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "hint": "Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "message": "This check failed and has no result.", + "payload_json": { + "error": { + "code": "pipeline_failed", + "fix": "Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "message": "This check failed and has no result.", + "status": 409 + } + }, + "request_id": "", + "retryable": false, + "status_code": 409, + "task_id": "7cff18da2d979d6370e54a160be121ad", + "type": "LenzPipelineError" + } +} diff --git a/tests/fixtures/parity/expected/verify__verification_not_ready_409.json b/tests/fixtures/parity/expected/verify__verification_not_ready_409.json new file mode 100644 index 0000000..14d8183 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_not_ready_409.json @@ -0,0 +1,24 @@ +{ + "error": { + "cause": "This check is still running.", + "code": "verification_not_ready", + "doc_url": "https://lenz.io/docs/verify", + "fix": "Poll GET /verify/status/7cff18da2d979d6370e54a160be121ad until it completes, then read its result.", + "friendly_text": "This check is still running.\n Fix: Poll GET /verify/status/7cff18da2d979d6370e54a160be121ad until it completes, then read its result.", + "hint": "Poll GET /verify/status/7cff18da2d979d6370e54a160be121ad until it completes, then read its result.", + "message": "This check is still running.", + "payload_json": { + "error": { + "code": "not_ready", + "fix": "Poll GET /verify/status/7cff18da2d979d6370e54a160be121ad until it completes, then read its result.", + "message": "This check is still running.", + "status": 409 + } + }, + "request_id": "", + "status": "processing", + "status_code": 409, + "task_id": "7cff18da2d979d6370e54a160be121ad", + "type": "LenzVerificationNotReadyError" + } +} diff --git a/tests/fixtures/parity/expected/verify__verification_not_yours_404.json b/tests/fixtures/parity/expected/verify__verification_not_yours_404.json new file mode 100644 index 0000000..41573fe --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_not_yours_404.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__verification_public_anonymous.json b/tests/fixtures/parity/expected/verify__verification_public_anonymous.json new file mode 100644 index 0000000..ab58772 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_public_anonymous.json @@ -0,0 +1,80 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "public", + "warnings": [ + "Relies on limited sources" + ] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"public\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": null\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_public_of_another_user.json b/tests/fixtures/parity/expected/verify__verification_public_of_another_user.json new file mode 100644 index 0000000..d21e90e --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_public_of_another_user.json @@ -0,0 +1,92 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "public", + "warnings": [ + "Relies on limited sources" + ] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"public\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/verify__verification_unknown_task_404.json b/tests/fixtures/parity/expected/verify__verification_unknown_task_404.json new file mode 100644 index 0000000..41573fe --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_unknown_task_404.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__verification_zero_retention_expired_410.json b/tests/fixtures/parity/expected/verify__verification_zero_retention_expired_410.json new file mode 100644 index 0000000..99f659b --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_zero_retention_expired_410.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "This verification is no longer available: its account removes verifications after a set period.", + "code": "purged", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Its account's retention period removed it. A certificate issued for it is still available.", + "friendly_text": "This verification is no longer available: its account removes verifications after a set period.\n Fix: Its account's retention period removed it. A certificate issued for it is still available.", + "message": "This verification is no longer available: its account removes verifications after a set period.", + "payload_json": { + "error": { + "code": "gone", + "fix": "Its account's retention period removed it. A certificate issued for it is still available.", + "message": "This verification is no longer available: its account removes verifications after a set period.", + "status": 410 + } + }, + "purged_at": "2026-10-01T09:07:00.123456+00:00", + "request_id": "", + "status_code": 410, + "type": "LenzGoneError" + } +} diff --git a/tests/fixtures/parity/expected/verify__verification_zero_retention_served.json b/tests/fixtures/parity/expected/verify__verification_zero_retention_served.json new file mode 100644 index 0000000..e12b093 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__verification_zero_retention_served.json @@ -0,0 +1,92 @@ +{ + "dump": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is well supported by evidence.", + "key_finding": "The Earth is approximately spherical.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical.\n\nThe claim is well supported by evidence.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical.\n\nThe claim is well supported by evidence.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical.\",\n \"executive_summary\": \"The claim is well supported by evidence.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" +} diff --git a/tests/fixtures/parity/expected/webhook__certificate_timestamped.json b/tests/fixtures/parity/expected/webhook__certificate_timestamped.json new file mode 100644 index 0000000..49e54c1 --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__certificate_timestamped.json @@ -0,0 +1,23 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "coverage": { + "aggregate": 500000, + "as_of": "2026-09-03T10:00:00+00:00", + "cap": 10000, + "certificate_id": "def7232d27eda03cf261569aee9948c5", + "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "currency": "EUR", + "reasons": [], + "status": "covered", + "terms_version": "v1" + }, + "delivered_at": "2026-10-01T09:28:00.123456+00:00", + "event": "certificate.timestamped", + "status": "completed", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "type": "CertificateTimestamped", + "verification_id": "68ca4aaf" + } +} diff --git a/tests/fixtures/parity/expected/webhook__certificate_timestamped_review_child.json b/tests/fixtures/parity/expected/webhook__certificate_timestamped_review_child.json new file mode 100644 index 0000000..49e54c1 --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__certificate_timestamped_review_child.json @@ -0,0 +1,23 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "coverage": { + "aggregate": 500000, + "as_of": "2026-09-03T10:00:00+00:00", + "cap": 10000, + "certificate_id": "def7232d27eda03cf261569aee9948c5", + "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "currency": "EUR", + "reasons": [], + "status": "covered", + "terms_version": "v1" + }, + "delivered_at": "2026-10-01T09:28:00.123456+00:00", + "event": "certificate.timestamped", + "status": "completed", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "type": "CertificateTimestamped", + "verification_id": "68ca4aaf" + } +} diff --git a/tests/fixtures/parity/expected/webhook__citecheck_completed.json b/tests/fixtures/parity/expected/webhook__citecheck_completed.json new file mode 100644 index 0000000..7044240 --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__citecheck_completed.json @@ -0,0 +1,135 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "citecheck": { + "citation_failures": [], + "citation_issues": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": null, + "finding": "contradicted", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "position": null, + "quotes": [], + "rationale": "The page states it.", + "reference": "https://example.gov/report-2024", + "snippet": "The source says so.", + "source": "support", + "statement": "Unemployment fell to 4.1% in 2024." + } + ], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "contradicted", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": { + "finding": "contradicted", + "is_issue": true, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "98c0e7d5", + "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:28:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "issues_found", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 1, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "citecheck_id": "98c0e7d5", + "delivered_at": "2026-10-01T09:42:00.123456+00:00", + "event": "citecheck.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "status": "completed", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "type": "CitecheckEvent", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__citecheck_failed.json b/tests/fixtures/parity/expected/webhook__citecheck_failed.json new file mode 100644 index 0000000..aaa4c74 --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__citecheck_failed.json @@ -0,0 +1,48 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "citecheck": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "citecheck_id": "98c0e7d5", + "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:28:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "no_citations", + "hint": "The text has no citation to check: no link, DOI or numbered reference with one.", + "retryable": false + }, + "language": "en", + "more_citations": null, + "outcome": "unchecked", + "policy": { + "max_citations": 20 + }, + "poll_after_seconds": null, + "status": "failed", + "summary": { + "citation_checks": null, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null + } + }, + "citecheck_id": "98c0e7d5", + "delivered_at": "2026-10-01T09:42:00.123456+00:00", + "event": "citecheck.failed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "status": "failed", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "type": "CitecheckEvent", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__review_completed.json b/tests/fixtures/parity/expected/webhook__review_completed.json new file mode 100644 index 0000000..4e39f6b --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__review_completed.json @@ -0,0 +1,157 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T10:03:00.123456+00:00", + "event": "review.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T09:56:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "task_id": "5ccac77f53ff49328ec134fb29d66542", + "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "verdict": "False", + "verification_id": "8ceed6f0", + "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", + "visibility": "private", + "warnings": [ + "w1" + ] + } + } + ], + "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:28:00.123456Z", + "credits": { + "charged": 11 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "verdict": "False", + "verification_id": "8ceed6f0", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "8cb2f001", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 1, + "failed": 0, + "planned": 1 + } + }, + "view": "full" + }, + "review_id": "8cb2f001", + "status": "completed", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "type": "ReviewEvent", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__review_completed_key_default_url.json b/tests/fixtures/parity/expected/webhook__review_completed_key_default_url.json new file mode 100644 index 0000000..61e1a22 --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__review_completed_key_default_url.json @@ -0,0 +1,106 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T09:42:00.123456+00:00", + "event": "review.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:28:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "8cb2f001", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "review_id": "8cb2f001", + "status": "completed", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "type": "ReviewEvent", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__review_completed_oversized_rebuilt.json b/tests/fixtures/parity/expected/webhook__review_completed_oversized_rebuilt.json new file mode 100644 index 0000000..9fd5c6f --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__review_completed_oversized_rebuilt.json @@ -0,0 +1,15 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "", + "event": "review.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review": null, + "review_id": "8cb2f001", + "status": "completed", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "type": "ReviewEvent", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__review_failed.json b/tests/fixtures/parity/expected/webhook__review_failed.json new file mode 100644 index 0000000..08af731 --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__review_failed.json @@ -0,0 +1,74 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T09:42:00.123456+00:00", + "event": "review.failed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:28:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "no_claim", + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", + "retryable": false + }, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": "unchecked", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "8cb2f001", + "status": "failed", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "review_id": "8cb2f001", + "status": "failed", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "type": "ReviewEvent", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_completed.json b/tests/fixtures/parity/expected/webhook__verification_completed.json new file mode 100644 index 0000000..aa45bf9 --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_completed.json @@ -0,0 +1,103 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T09:28:00.123456+00:00", + "event": "verification.completed", + "result": { + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "focus_area": "Evidence", + "panelist_name": "Reviewer A", + "reasoning": "Both sources place the tower in Paris.", + "score": 1.0, + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "focus_area": "Evidence", + "panelist_name": "Reviewer B", + "reasoning": "The encyclopedia entry is unambiguous.", + "score": 2.0, + "warnings": [] + } + ], + "debate_con": { + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source.", + "role": "con" + }, + "debate_pro": { + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable.", + "role": "pro" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "key_finding": "The Eiffel Tower is in Paris.", + "language": "en", + "lenz_score": 1, + "modified_at": null, + "presumed_intent": "Check where a landmark is.", + "sources": [ + { + "date": "2025-01-15", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower" + }, + { + "date": "", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris" + } + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "verdict": "False", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Only two sources were found." + ] + }, + "status": "completed", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "type": "VerificationCompleted", + "verification_id": "68ca4aaf" + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_completed_in_batch.json b/tests/fixtures/parity/expected/webhook__verification_completed_in_batch.json new file mode 100644 index 0000000..e6dd56f --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_completed_in_batch.json @@ -0,0 +1,103 @@ +{ + "event": { + "attempt": 1, + "batch_id": "4ee0c3aa1b671eaa", + "delivered_at": "2026-10-01T09:35:00.123456+00:00", + "event": "verification.completed", + "result": { + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "focus_area": "Evidence", + "panelist_name": "Reviewer A", + "reasoning": "Both sources place the tower in Paris.", + "score": 1.0, + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "focus_area": "Evidence", + "panelist_name": "Reviewer B", + "reasoning": "The encyclopedia entry is unambiguous.", + "score": 2.0, + "warnings": [] + } + ], + "debate_con": { + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source.", + "role": "con" + }, + "debate_pro": { + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable.", + "role": "pro" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:28:00.123456+00:00", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "key_finding": "The Eiffel Tower is in Paris.", + "language": "en", + "lenz_score": 1, + "modified_at": null, + "presumed_intent": "Check where a landmark is.", + "sources": [ + { + "date": "2025-01-15", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower" + }, + { + "date": "", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris" + } + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "verdict": "False", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Only two sources were found." + ] + }, + "status": "completed", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "type": "VerificationCompleted", + "verification_id": "68ca4aaf" + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..c050dad --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,103 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T09:35:00.123456+00:00", + "event": "verification.completed", + "result": { + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "focus_area": "Evidence", + "panelist_name": "Reviewer A", + "reasoning": "Both sources place the tower in Paris.", + "score": 1.0, + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "focus_area": "Evidence", + "panelist_name": "Reviewer B", + "reasoning": "The encyclopedia entry is unambiguous.", + "score": 2.0, + "warnings": [] + } + ], + "debate_con": { + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source.", + "role": "con" + }, + "debate_pro": { + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable.", + "role": "pro" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "key_finding": "The Eiffel Tower is in Paris.", + "language": "en", + "lenz_score": 1, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Check where a landmark is.", + "sources": [ + { + "date": "2025-01-15", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower" + }, + { + "date": "", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris" + } + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "verdict": "False", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Only two sources were found." + ] + }, + "status": "completed", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "type": "VerificationCompleted", + "verification_id": "68ca4aaf" + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..78e81e6 --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_same_day_hours_apart.json @@ -0,0 +1,103 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T09:28:00.123456+00:00", + "event": "verification.completed", + "result": { + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "focus_area": "Evidence", + "panelist_name": "Reviewer A", + "reasoning": "Both sources place the tower in Paris.", + "score": 1.0, + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "focus_area": "Evidence", + "panelist_name": "Reviewer B", + "reasoning": "The encyclopedia entry is unambiguous.", + "score": 2.0, + "warnings": [] + } + ], + "debate_con": { + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source.", + "role": "con" + }, + "debate_pro": { + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable.", + "role": "pro" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "key_finding": "The Eiffel Tower is in Paris.", + "language": "en", + "lenz_score": 1, + "modified_at": null, + "presumed_intent": "Check where a landmark is.", + "sources": [ + { + "date": "2025-01-15", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower" + }, + { + "date": "", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris" + } + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "verdict": "False", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Only two sources were found." + ] + }, + "status": "completed", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "type": "VerificationCompleted", + "verification_id": "68ca4aaf" + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_failed_insufficient_evidence.json b/tests/fixtures/parity/expected/webhook__verification_failed_insufficient_evidence.json new file mode 100644 index 0000000..81bf11e --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_failed_insufficient_evidence.json @@ -0,0 +1,15 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T09:14:00.123456+00:00", + "error": "research_insufficient", + "event": "verification.failed", + "failure_class": "insufficient_evidence", + "retryable": false, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "type": "VerificationFailed", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_failed_not_a_claim.json b/tests/fixtures/parity/expected/webhook__verification_failed_not_a_claim.json new file mode 100644 index 0000000..15e827d --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_failed_not_a_claim.json @@ -0,0 +1,15 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T09:14:00.123456+00:00", + "error": "not_a_claim", + "event": "verification.failed", + "failure_class": "invalid_input", + "retryable": false, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "type": "VerificationFailed", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_failed_upstream_unavailable.json b/tests/fixtures/parity/expected/webhook__verification_failed_upstream_unavailable.json new file mode 100644 index 0000000..6ec1bcb --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_failed_upstream_unavailable.json @@ -0,0 +1,15 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T09:14:00.123456+00:00", + "error": "framing_failed", + "event": "verification.failed", + "failure_class": "upstream_unavailable", + "retryable": true, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "type": "VerificationFailed", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_needs_input_multi_claim.json b/tests/fixtures/parity/expected/webhook__verification_needs_input_multi_claim.json new file mode 100644 index 0000000..55e2dc8 --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_needs_input_multi_claim.json @@ -0,0 +1,27 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T09:14:00.123456+00:00", + "event": "verification.needs_input", + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.", + "needs_input": { + "claims": [ + { + "domain": "", + "text": "The Earth is round." + }, + { + "domain": "Science", + "text": "The Moon is made of cheese." + } + ], + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.", + "reason": "multi_claim" + }, + "status": "needs_input", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "type": "VerificationNeedsInput", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/legacy/account__library_empty.json b/tests/fixtures/parity/legacy/account__library_empty.json new file mode 100644 index 0000000..b419316 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__library_empty.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [], + "total": 0, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/account__library_item_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/account__library_item_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..e59c0d7 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__library_item_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "A library claim.", + "domain": "", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "language": "en" + } + ], + "total": 1, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/account__library_item_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/account__library_item_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..5fb5763 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__library_item_modified_at_same_day_hours_apart.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "A library claim.", + "domain": "", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "modified_at": null, + "language": "en" + } + ], + "total": 1, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/account__library_items.json b/tests/fixtures/parity/legacy/account__library_items.json new file mode 100644 index 0000000..2868a2e --- /dev/null +++ b/tests/fixtures/parity/legacy/account__library_items.json @@ -0,0 +1,60 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "Library claim 0.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "language": "en" + }, + { + "verification_id": "7c83247c", + "claim": "Library claim 1.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:28:00.123456+00:00", + "modified_at": null, + "language": "en" + }, + { + "verification_id": "b79019e4", + "claim": "Library claim 2.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:42:00.123456+00:00", + "modified_at": null, + "language": "en" + } + ], + "total": 3, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/account__library_no_match.json b/tests/fixtures/parity/legacy/account__library_no_match.json new file mode 100644 index 0000000..b419316 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__library_no_match.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [], + "total": 0, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/account__library_page_past_end.json b/tests/fixtures/parity/legacy/account__library_page_past_end.json new file mode 100644 index 0000000..86d64c7 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__library_page_past_end.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [], + "total": 1, + "page": 2, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/account__library_paginated_second_page.json b/tests/fixtures/parity/legacy/account__library_paginated_second_page.json new file mode 100644 index 0000000..9529811 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__library_paginated_second_page.json @@ -0,0 +1,45 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "Paged claim 020.", + "domain": "", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "language": "en" + }, + { + "verification_id": "7c83247c", + "claim": "Paged claim 021.", + "domain": "", + "entities": [], + "verdict": "True", + "confidence": "low", + "lenz_score": 10, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:28:00.123456+00:00", + "modified_at": null, + "language": "en" + } + ], + "total": 22, + "page": 2, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/account__me_usage_extra_credits.json b/tests/fixtures/parity/legacy/account__me_usage_extra_credits.json new file mode 100644 index 0000000..e07e31f --- /dev/null +++ b/tests/fixtures/parity/legacy/account__me_usage_extra_credits.json @@ -0,0 +1,66 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "credits": { + "total": 350, + "used": 0, + "remaining": 350, + "extra": 250, + "bonus": 250, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "verify": { + "quota_used": 0, + "quota_total": 35, + "quota_remaining": 35, + "bonus": 25, + "credits": 25, + "remaining": 35 + }, + "ask": { + "quota_used": 0, + "quota_total": 350, + "quota_remaining": 350, + "bonus": 250, + "credits": 250, + "remaining": 350 + }, + "assess": { + "quota_used": 0, + "quota_total": 350, + "quota_remaining": 350, + "bonus": 250, + "credits": 250, + "remaining": 350 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/legacy/account__me_usage_extra_only.json b/tests/fixtures/parity/legacy/account__me_usage_extra_only.json new file mode 100644 index 0000000..0e00cac --- /dev/null +++ b/tests/fixtures/parity/legacy/account__me_usage_extra_only.json @@ -0,0 +1,66 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "credits": { + "total": 137, + "used": 100, + "remaining": 37, + "extra": 37, + "bonus": 37, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "verify": { + "quota_used": 10, + "quota_total": 13, + "quota_remaining": 3, + "bonus": 3, + "credits": 3, + "remaining": 3 + }, + "ask": { + "quota_used": 100, + "quota_total": 137, + "quota_remaining": 37, + "bonus": 37, + "credits": 37, + "remaining": 37 + }, + "assess": { + "quota_used": 100, + "quota_total": 137, + "quota_remaining": 37, + "bonus": 37, + "credits": 37, + "remaining": 37 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/legacy/account__me_usage_extract_calls.json b/tests/fixtures/parity/legacy/account__me_usage_extract_calls.json new file mode 100644 index 0000000..335d0f1 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__me_usage_extract_calls.json @@ -0,0 +1,66 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "credits": { + "total": 100, + "used": 0, + "remaining": 100, + "extra": 0, + "bonus": 0, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "verify": { + "quota_used": 0, + "quota_total": 10, + "quota_remaining": 10, + "bonus": 0, + "credits": 0, + "remaining": 10 + }, + "ask": { + "quota_used": 0, + "quota_total": 100, + "quota_remaining": 100, + "bonus": 0, + "credits": 0, + "remaining": 100 + }, + "assess": { + "quota_used": 0, + "quota_total": 100, + "quota_remaining": 100, + "bonus": 0, + "credits": 0, + "remaining": 100 + }, + "extract": { + "calls_today": 7, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/legacy/account__me_usage_free.json b/tests/fixtures/parity/legacy/account__me_usage_free.json new file mode 100644 index 0000000..6a23d7a --- /dev/null +++ b/tests/fixtures/parity/legacy/account__me_usage_free.json @@ -0,0 +1,66 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "credits": { + "total": 100, + "used": 0, + "remaining": 100, + "extra": 0, + "bonus": 0, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "verify": { + "quota_used": 0, + "quota_total": 10, + "quota_remaining": 10, + "bonus": 0, + "credits": 0, + "remaining": 10 + }, + "ask": { + "quota_used": 0, + "quota_total": 100, + "quota_remaining": 100, + "bonus": 0, + "credits": 0, + "remaining": 100 + }, + "assess": { + "quota_used": 0, + "quota_total": 100, + "quota_remaining": 100, + "bonus": 0, + "credits": 0, + "remaining": 100 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/legacy/account__me_usage_free_partly_spent.json b/tests/fixtures/parity/legacy/account__me_usage_free_partly_spent.json new file mode 100644 index 0000000..8f43c97 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__me_usage_free_partly_spent.json @@ -0,0 +1,66 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "credits": { + "total": 100, + "used": 17, + "remaining": 83, + "extra": 0, + "bonus": 0, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "verify": { + "quota_used": 2, + "quota_total": 10, + "quota_remaining": 8, + "bonus": 0, + "credits": 0, + "remaining": 8 + }, + "ask": { + "quota_used": 17, + "quota_total": 100, + "quota_remaining": 83, + "bonus": 0, + "credits": 0, + "remaining": 83 + }, + "assess": { + "quota_used": 17, + "quota_total": 100, + "quota_remaining": 83, + "bonus": 0, + "credits": 0, + "remaining": 83 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/legacy/account__me_usage_plus.json b/tests/fixtures/parity/legacy/account__me_usage_plus.json new file mode 100644 index 0000000..e49254d --- /dev/null +++ b/tests/fixtures/parity/legacy/account__me_usage_plus.json @@ -0,0 +1,66 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "plus", + "plan_label": "Plus", + "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "credits": { + "total": 500, + "used": 0, + "remaining": 500, + "extra": 0, + "bonus": 0, + "resets_at": "2026-10-01T09:07:00.123456+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "verify": { + "quota_used": 0, + "quota_total": 50, + "quota_remaining": 50, + "bonus": 0, + "credits": 0, + "remaining": 50 + }, + "ask": { + "quota_used": 0, + "quota_total": 500, + "quota_remaining": 500, + "bonus": 0, + "credits": 0, + "remaining": 500 + }, + "assess": { + "quota_used": 0, + "quota_total": 500, + "quota_remaining": 500, + "bonus": 0, + "credits": 0, + "remaining": 500 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/legacy/account__me_usage_pro.json b/tests/fixtures/parity/legacy/account__me_usage_pro.json new file mode 100644 index 0000000..4c0fab9 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__me_usage_pro.json @@ -0,0 +1,66 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "pro", + "plan_label": "Pro", + "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "credits": { + "total": 5000, + "used": 0, + "remaining": 5000, + "extra": 0, + "bonus": 0, + "resets_at": "2026-10-01T09:07:00.123456+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "verify": { + "quota_used": 0, + "quota_total": 500, + "quota_remaining": 500, + "bonus": 0, + "credits": 0, + "remaining": 500 + }, + "ask": { + "quota_used": 0, + "quota_total": 5000, + "quota_remaining": 5000, + "bonus": 0, + "credits": 0, + "remaining": 5000 + }, + "assess": { + "quota_used": 0, + "quota_total": 5000, + "quota_remaining": 5000, + "bonus": 0, + "credits": 0, + "remaining": 5000 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/legacy/account__me_usage_pro_extra.json b/tests/fixtures/parity/legacy/account__me_usage_pro_extra.json new file mode 100644 index 0000000..a15d613 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__me_usage_pro_extra.json @@ -0,0 +1,66 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "pro", + "plan_label": "Pro", + "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "credits": { + "total": 6000, + "used": 0, + "remaining": 6000, + "extra": 1000, + "bonus": 1000, + "resets_at": "2026-10-01T09:07:00.123456+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "verify": { + "quota_used": 0, + "quota_total": 600, + "quota_remaining": 600, + "bonus": 100, + "credits": 100, + "remaining": 600 + }, + "ask": { + "quota_used": 0, + "quota_total": 6000, + "quota_remaining": 6000, + "bonus": 1000, + "credits": 1000, + "remaining": 6000 + }, + "assess": { + "quota_used": 0, + "quota_total": 6000, + "quota_remaining": 6000, + "bonus": 1000, + "credits": 1000, + "remaining": 6000 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/legacy/account__me_usage_stale_quota_row.json b/tests/fixtures/parity/legacy/account__me_usage_stale_quota_row.json new file mode 100644 index 0000000..6a23d7a --- /dev/null +++ b/tests/fixtures/parity/legacy/account__me_usage_stale_quota_row.json @@ -0,0 +1,66 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T09:07:00+00:00", + "credits": { + "total": 100, + "used": 0, + "remaining": 100, + "extra": 0, + "bonus": 0, + "resets_at": "2026-10-01T09:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "verify": { + "quota_used": 0, + "quota_total": 10, + "quota_remaining": 10, + "bonus": 0, + "credits": 0, + "remaining": 10 + }, + "ask": { + "quota_used": 0, + "quota_total": 100, + "quota_remaining": 100, + "bonus": 0, + "credits": 0, + "remaining": 100 + }, + "assess": { + "quota_used": 0, + "quota_total": 100, + "quota_remaining": 100, + "bonus": 0, + "credits": 0, + "remaining": 100 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + } +} diff --git a/tests/fixtures/parity/legacy/assess__401_no_key.json b/tests/fixtures/parity/legacy/assess__401_no_key.json new file mode 100644 index 0000000..8dd2fb4 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__401_no_key.json @@ -0,0 +1,11 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized" + } +} diff --git a/tests/fixtures/parity/legacy/assess__402_no_credits.json b/tests/fixtures/parity/legacy/assess__402_no_credits.json new file mode 100644 index 0000000..1cd3038 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__402_no_credits.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining /assess units.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/legacy/assess__422_blank_item.json b/tests/fixtures/parity/legacy/assess__422_blank_item.json new file mode 100644 index 0000000..af5a22a --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__422_blank_item.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claims[1] is blank.", + "code": "blank_item" + } +} diff --git a/tests/fixtures/parity/legacy/assess__422_blank_text.json b/tests/fixtures/parity/legacy/assess__422_blank_text.json new file mode 100644 index 0000000..1ebb88e --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__422_blank_text.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Text is required." + } +} diff --git a/tests/fixtures/parity/legacy/assess__422_input_conflict.json b/tests/fixtures/parity/legacy/assess__422_input_conflict.json new file mode 100644 index 0000000..c811d89 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__422_input_conflict.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Send either `claim` (one text) or `claims` (a list of claims), not both.", + "code": "input_conflict" + } +} diff --git a/tests/fixtures/parity/legacy/assess__422_item_too_long.json b/tests/fixtures/parity/legacy/assess__422_item_too_long.json new file mode 100644 index 0000000..21e6f19 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__422_item_too_long.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claims[1] is 2001 characters; each claim may be at most 2000. Send a document to /extract first, then assess its claims.", + "code": "item_too_long" + } +} diff --git a/tests/fixtures/parity/legacy/assess__422_no_input_field.json b/tests/fixtures/parity/legacy/assess__422_no_input_field.json new file mode 100644 index 0000000..f862968 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__422_no_input_field.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "missing", + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/assess__422_too_many_items.json b/tests/fixtures/parity/legacy/assess__422_too_many_items.json new file mode 100644 index 0000000..80d556a --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__422_too_many_items.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "At most 20 claims per call; got 21. Split the list.", + "code": "too_many_items" + } +} diff --git a/tests/fixtures/parity/legacy/assess__422_wrong_type_claim.json b/tests/fixtures/parity/legacy/assess__422_wrong_type_claim.json new file mode 100644 index 0000000..d8d8c87 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__422_wrong_type_claim.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "string_type", + "loc": [ + "body", + "payload", + "claim" + ], + "msg": "Input should be a valid string" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/assess__422_wrong_type_claims.json b/tests/fixtures/parity/legacy/assess__422_wrong_type_claims.json new file mode 100644 index 0000000..a997f8c --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__422_wrong_type_claims.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "list_type", + "loc": [ + "body", + "payload", + "claims" + ], + "msg": "Input should be a valid list" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/assess__502_framing_failed.json b/tests/fixtures/parity/legacy/assess__502_framing_failed.json new file mode 100644 index 0000000..9b6d047 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__502_framing_failed.json @@ -0,0 +1,13 @@ +{ + "status": 502, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Framing failed", + "code": "framing_failed", + "error": "framing_failed" + } +} diff --git a/tests/fixtures/parity/legacy/assess__503_capacity.json b/tests/fixtures/parity/legacy/assess__503_capacity.json new file mode 100644 index 0000000..de01494 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__503_capacity.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "100", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": 100, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/assess__503_list_all_upstream_unavailable.json b/tests/fixtures/parity/legacy/assess__503_list_all_upstream_unavailable.json new file mode 100644 index 0000000..9e74dd2 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__503_list_all_upstream_unavailable.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Our model providers are temporarily unavailable. Please retry shortly. Nothing was charged.", + "code": "upstream_unavailable", + "retry_after": 90, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/assess__503_upstream_unavailable.json b/tests/fixtures/parity/legacy/assess__503_upstream_unavailable.json new file mode 100644 index 0000000..b308e0c --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__503_upstream_unavailable.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Our model providers are temporarily unavailable. Please retry shortly.", + "code": "upstream_unavailable", + "retry_after": 90, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/assess__deep_tier_hit.json b/tests/fixtures/parity/legacy/assess__deep_tier_hit.json new file mode 100644 index 0000000..a5e696a --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__deep_tier_hit.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "Water boils at 100C.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": "https://lenz.io/api/v1/verifications/f3436f50", + "rationale": "The claim is verified.", + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__idempotency_body_mismatch.json b/tests/fixtures/parity/legacy/assess__idempotency_body_mismatch.json new file mode 100644 index 0000000..ef04562 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__idempotency_body_mismatch.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body." + } +} diff --git a/tests/fixtures/parity/legacy/assess__idempotency_first.json b/tests/fixtures/parity/legacy/assess__idempotency_first.json new file mode 100644 index 0000000..bac5c15 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__idempotency_first.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "The Earth orbits the Sun.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__idempotency_replay.json b/tests/fixtures/parity/legacy/assess__idempotency_replay.json new file mode 100644 index 0000000..bac5c15 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__idempotency_replay.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "The Earth orbits the Sun.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__list_all_error_rows.json b/tests/fixtures/parity/legacy/assess__list_all_error_rows.json new file mode 100644 index 0000000..ba846f5 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__list_all_error_rows.json @@ -0,0 +1,42 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "hi", + "language": "en", + "verdict": "Error", + "confidence": "low", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": "no_claim", + "candidate_claims": [], + "identified_claims": [], + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims." + }, + { + "claim": "hello", + "language": "en", + "verdict": "Error", + "confidence": "low", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": "no_claim", + "candidate_claims": [], + "identified_claims": [], + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims." + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__list_compound_item.json b/tests/fixtures/parity/legacy/assess__list_compound_item.json new file mode 100644 index 0000000..2a9d928 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__list_compound_item.json @@ -0,0 +1,45 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "Primary claim.", + "language": "en", + "verdict": "Mostly False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [ + "Second claim.", + "Third claim." + ], + "hint": "Assessed the main claim only. Send identified_claims as their own items to check the rest." + }, + { + "claim": "A plain claim.", + "language": "en", + "verdict": "Mostly False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__list_mixed_rows.json b/tests/fixtures/parity/legacy/assess__list_mixed_rows.json new file mode 100644 index 0000000..5c4bfe1 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__list_mixed_rows.json @@ -0,0 +1,70 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "Water boils at 100 C at sea level.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "hello there", + "language": "en", + "verdict": "Error", + "confidence": "low", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": "no_claim", + "candidate_claims": [], + "identified_claims": [], + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims." + }, + { + "claim": "vendor is down", + "language": "en", + "verdict": "Error", + "confidence": "low", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": "upstream_unavailable", + "candidate_claims": [], + "identified_claims": [], + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged." + }, + { + "claim": "cannot frame", + "language": "en", + "verdict": "Error", + "confidence": "low", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": "framing_failed", + "candidate_claims": [], + "identified_claims": [], + "hint": "This item could not be processed; retrying it as-is will not help. Send it rephrased as one factual statement; nothing was charged." + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__memo_hit.json b/tests/fixtures/parity/legacy/assess__memo_hit.json new file mode 100644 index 0000000..96a0c4d --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__memo_hit.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "The Danube flows through Vienna.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": "The river runs through the city.", + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__replay_later_200.json b/tests/fixtures/parity/legacy/assess__replay_later_200.json new file mode 100644 index 0000000..bac5c15 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__replay_later_200.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "The Earth orbits the Sun.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__single_no_claim.json b/tests/fixtures/parity/legacy/assess__single_no_claim.json new file mode 100644 index 0000000..b40abf7 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__single_no_claim.json @@ -0,0 +1,15 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [], + "error": "No verifiable claim detected", + "error_code": "no_claim", + "candidate_claims": [], + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__single_one_claim.json b/tests/fixtures/parity/legacy/assess__single_one_claim.json new file mode 100644 index 0000000..d27e7eb --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__single_one_claim.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "The registry reported 4,200 filings in 2024.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": "The registry lists 4,200 filings for 2024 and has not revised the figure.", + "dissent": "The registry figure is provisional, so the 2024 total cannot yet be confirmed.", + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__single_text_over_wave_more_claims.json b/tests/fixtures/parity/legacy/assess__single_text_over_wave_more_claims.json new file mode 100644 index 0000000..d4849fc --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__single_text_over_wave_more_claims.json @@ -0,0 +1,297 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "Claim number 0 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 1 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 2 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 3 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 4 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 5 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 6 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 7 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 8 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 9 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 10 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 11 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 12 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 13 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 14 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 15 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 16 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 17 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 18 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Claim number 19 is documented.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [ + "Claim number 20 is documented.", + "Claim number 21 is documented." + ] + } +} diff --git a/tests/fixtures/parity/legacy/assess__single_text_several_claims.json b/tests/fixtures/parity/legacy/assess__single_text_several_claims.json new file mode 100644 index 0000000..2db91ed --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__single_text_several_claims.json @@ -0,0 +1,56 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "Water boils at 100 C at sea level.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "The Moon is made of cheese.", + "language": "en", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "The Pacific is the deepest ocean.", + "language": "en", + "verdict": "Mostly True", + "confidence": "medium", + "verification_url": null, + "rationale": null, + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/assess__suggest_rewrite.json b/tests/fixtures/parity/legacy/assess__suggest_rewrite.json new file mode 100644 index 0000000..f4f7b54 --- /dev/null +++ b/tests/fixtures/parity/legacy/assess__suggest_rewrite.json @@ -0,0 +1,42 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "claims": [ + { + "claim": "Venus is the closest planet to the Sun.", + "language": "en", + "verdict": "False", + "confidence": "high", + "verification_url": null, + "rationale": "Mercury, not Venus, is the closest planet to the Sun.", + "dissent": null, + "suggested_rewrite": "Mercury is the closest planet to the Sun.", + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + }, + { + "claim": "Mercury is the closest planet to the Sun.", + "language": "en", + "verdict": "True", + "confidence": "high", + "verification_url": null, + "rationale": "Mercury is the innermost planet.", + "dissent": null, + "suggested_rewrite": null, + "error_code": null, + "candidate_claims": [], + "identified_claims": [], + "hint": null + } + ], + "error": null, + "more_claims": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__402_no_credits.json b/tests/fixtures/parity/legacy/citecheck__402_no_credits.json new file mode 100644 index 0000000..200f42b --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__402_no_credits.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining credits for citation checks.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 100, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 100, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_empty_body.json b/tests/fixtures/parity/legacy/citecheck__422_empty_body.json new file mode 100644 index 0000000..6f9d742 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_empty_body.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload: Value error, send exactly one of text and pairs", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload" + ], + "msg": "Value error, send exactly one of text and pairs" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_invalid_doi.json b/tests/fixtures/parity/legacy/citecheck__422_invalid_doi.json new file mode 100644 index 0000000..3026138 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_invalid_doi.json @@ -0,0 +1,24 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.pairs.0.doi: Send the DOI alone, like 10.1038/nature12373.", + "code": "invalid_doi", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0, + "doi" + ], + "msg": "Send the DOI alone, like 10.1038/nature12373." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_max_citations_over_20.json b/tests/fixtures/parity/legacy/citecheck__422_max_citations_over_20.json new file mode 100644 index 0000000..279eba0 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_max_citations_over_20.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.max_citations: Input should be less than or equal to 20", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "max_citations" + ], + "msg": "Input should be less than or equal to 20" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_max_citations_with_pairs.json b/tests/fixtures/parity/legacy/citecheck__422_max_citations_with_pairs.json new file mode 100644 index 0000000..bd0828b --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_max_citations_with_pairs.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload: Value error, max_citations goes with text: every pair is checked", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload" + ], + "msg": "Value error, max_citations goes with text: every pair is checked" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_pair_bad_url_scheme.json b/tests/fixtures/parity/legacy/citecheck__422_pair_bad_url_scheme.json new file mode 100644 index 0000000..c7046cc --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_pair_bad_url_scheme.json @@ -0,0 +1,24 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.pairs.0.url: Value error, url: an http or https link", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0, + "url" + ], + "msg": "Value error, url: an http or https link" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_pair_no_source.json b/tests/fixtures/parity/legacy/citecheck__422_pair_no_source.json new file mode 100644 index 0000000..10ddcdb --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_pair_no_source.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.pairs.0: Value error, send exactly one of url and doi", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0 + ], + "msg": "Value error, send exactly one of url and doi" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_pair_url_and_doi.json b/tests/fixtures/parity/legacy/citecheck__422_pair_url_and_doi.json new file mode 100644 index 0000000..10ddcdb --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_pair_url_and_doi.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.pairs.0: Value error, send exactly one of url and doi", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0 + ], + "msg": "Value error, send exactly one of url and doi" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_pairs_empty.json b/tests/fixtures/parity/legacy/citecheck__422_pairs_empty.json new file mode 100644 index 0000000..2df0724 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_pairs_empty.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.pairs: Value error, pairs: 1 to 20 items", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs" + ], + "msg": "Value error, pairs: 1 to 20 items" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_pairs_over_20.json b/tests/fixtures/parity/legacy/citecheck__422_pairs_over_20.json new file mode 100644 index 0000000..2df0724 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_pairs_over_20.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.pairs: Value error, pairs: 1 to 20 items", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs" + ], + "msg": "Value error, pairs: 1 to 20 items" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_quote_not_in_statement.json b/tests/fixtures/parity/legacy/citecheck__422_quote_not_in_statement.json new file mode 100644 index 0000000..462190c --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_quote_not_in_statement.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.pairs.0: Each quote must be words of its statement.", + "code": "quote_not_in_statement", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0 + ], + "msg": "Each quote must be words of its statement." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_text_and_pairs.json b/tests/fixtures/parity/legacy/citecheck__422_text_and_pairs.json new file mode 100644 index 0000000..6f9d742 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_text_and_pairs.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload: Value error, send exactly one of text and pairs", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload" + ], + "msg": "Value error, send exactly one of text and pairs" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_unknown_field.json b/tests/fixtures/parity/legacy/citecheck__422_unknown_field.json new file mode 100644 index 0000000..cb50c65 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_unknown_field.json @@ -0,0 +1,24 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.pairs.0.extra: Extra inputs are not permitted", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "pairs", + 0, + "extra" + ], + "msg": "Extra inputs are not permitted" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__422_url_input.json b/tests/fixtures/parity/legacy/citecheck__422_url_input.json new file mode 100644 index 0000000..d5ddd25 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_url_input.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Send the page's text, with its links, to check the sources it cites.", + "code": "url_input", + "errors": [ + { + "loc": [ + "body", + "text" + ], + "msg": "Send the page's text, with its links, to check the sources it cites." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__429_citecheck_in_flight.json b/tests/fixtures/parity/legacy/citecheck__429_citecheck_in_flight.json new file mode 100644 index 0000000..5222210 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__429_citecheck_in_flight.json @@ -0,0 +1,14 @@ +{ + "status": 429, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This account already has 3 citation checks running. Wait for one to finish.", + "code": "citecheck_in_flight", + "retry_after_seconds": 60 + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__503_capacity.json b/tests/fixtures/parity/legacy/citecheck__503_capacity.json new file mode 100644 index 0000000..adcc209 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__503_capacity.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": 90, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__503_citations_unavailable.json b/tests/fixtures/parity/legacy/citecheck__503_citations_unavailable.json new file mode 100644 index 0000000..ea4e7b8 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__503_citations_unavailable.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "300", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Citation checking is switched off right now. Retry later; nothing was charged.", + "code": "citations_unavailable", + "retry_after": 300, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_404_not_found.json b/tests/fixtures/parity/legacy/citecheck__get_404_not_found.json new file mode 100644 index 0000000..e0adfb3 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_404_not_found.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Citation check not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_404_review_id.json b/tests/fixtures/parity/legacy/citecheck__get_404_review_id.json new file mode 100644 index 0000000..e0adfb3 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_404_review_id.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Citation check not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_410_purged.json b/tests/fixtures/parity/legacy/citecheck__get_410_purged.json new file mode 100644 index 0000000..9fff981 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_410_purged.json @@ -0,0 +1,13 @@ +{ + "status": 410, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This check is no longer available: its account removes content after a set period.", + "code": "purged", + "purged_at": "2026-10-01T09:07:00.123456Z" + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_checking.json b/tests/fixtures/parity/legacy/citecheck__get_checking.json new file mode 100644 index 0000000..3c32986 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_checking.json @@ -0,0 +1,103 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "checking", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "poll_after_seconds": 10, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_reached": false, + "citation_checks": { + "checked": 0, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "pending", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "pending", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_clean.json b/tests/fixtures/parity/legacy/citecheck__get_completed_clean.json new file mode 100644 index 0000000..5e92112 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_clean.json @@ -0,0 +1,111 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 2 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_doi_pair.json b/tests/fixtures/parity/legacy/citecheck__get_completed_doi_pair.json new file mode 100644 index 0000000..2bdb1bf --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_doi_pair.json @@ -0,0 +1,76 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 1 + }, + "summary": { + "citations_found": 1, + "citations_selected": 1, + "citation_limit": 1, + "citation_limit_reached": false, + "citation_checks": { + "checked": 1, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 1 + }, + "citations": [ + { + "index": 0, + "reference": "10.1038/nature12373", + "cited_url": "https://doi.org/10.1038/nature12373", + "doi": "10.1038/nature12373", + "statement": "Diamond sensors measure heat in cells.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at None", + "page_published_date": null, + "page_language": "en", + "source_url": null, + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_incomplete.json b/tests/fixtures/parity/legacy/citecheck__get_completed_incomplete.json new file mode 100644 index 0000000..316b4d5 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_incomplete.json @@ -0,0 +1,127 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_reached": false, + "citation_checks": { + "checked": 1, + "unchecked": 0, + "failed": 1 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 1 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "failed", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": "The check failed on our side. Try again later.", + "failure": { + "hint": "The check failed on our side. Try again later.", + "docs_url": "https://lenz.io/docs/errors#internal", + "retryable": false, + "failure_class": "internal", + "failure_reason": "internal" + }, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [ + { + "citation_index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "failure": { + "hint": "The check failed on our side. Try again later.", + "docs_url": "https://lenz.io/docs/errors#internal", + "retryable": false, + "failure_class": "internal", + "failure_reason": "internal" + } + } + ], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_issues_found.json b/tests/fixtures/parity/legacy/citecheck__get_completed_issues_found.json new file mode 100644 index 0000000..75b7f7d --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_issues_found.json @@ -0,0 +1,141 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 20 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 1 + }, + "credits": { + "charged": 2 + }, + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "contradicted", + "source": "support", + "is_issue": true + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "contradicted", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [ + { + "citation_index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "finding": "contradicted", + "source": "support", + "snippet": "The source says so.", + "rationale": "The page states it.", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "failure": null + } + ], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_partly_supported.json b/tests/fixtures/parity/legacy/citecheck__get_completed_partly_supported.json new file mode 100644 index 0000000..5ae2366 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_partly_supported.json @@ -0,0 +1,111 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 2 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": { + "finding": "partly_supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "partly_supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_unchecked.json b/tests/fixtures/parity/legacy/citecheck__get_completed_unchecked.json new file mode 100644 index 0000000..4e53bd4 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_unchecked.json @@ -0,0 +1,111 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_reached": false, + "citation_checks": { + "checked": 0, + "unchecked": 2, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": { + "finding": "unchecked", + "source": null, + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "unchecked", + "snippet": null, + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": "no_text", + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": { + "finding": "unchecked", + "source": null, + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "unchecked", + "snippet": null, + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": "no_text", + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_failed_no_citations.json b/tests/fixtures/parity/legacy/citecheck__get_failed_no_citations.json new file mode 100644 index 0000000..c66a84e --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_failed_no_citations.json @@ -0,0 +1,42 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 20 + }, + "summary": { + "citations_found": null, + "citations_selected": null, + "citation_limit": 20, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [], + "citation_issues": [], + "citation_failures": [], + "failure": { + "failure_reason": "no_citations", + "failure_class": "invalid_input", + "retryable": false, + "hint": "The text has no citation to check: no link, DOI or numbered reference with one.", + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_failed_upstream_unavailable.json b/tests/fixtures/parity/legacy/citecheck__get_failed_upstream_unavailable.json new file mode 100644 index 0000000..2fba44d --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_failed_upstream_unavailable.json @@ -0,0 +1,148 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 20 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_reached": false, + "citation_checks": { + "checked": 0, + "unchecked": 0, + "failed": 2 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": null, + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "failed", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": "Lenz could not reach this source just now. Try again later.", + "failure": { + "hint": "Lenz could not reach this source just now. Try again later.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "retryable": true, + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable" + }, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": null, + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "failed", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": "Lenz could not reach this source just now. Try again later.", + "failure": { + "hint": "Lenz could not reach this source just now. Try again later.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "retryable": true, + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable" + }, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [ + { + "citation_index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": { + "hint": "Lenz could not reach this source just now. Try again later.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "retryable": true, + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable" + } + }, + { + "citation_index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "failure": { + "hint": "Lenz could not reach this source just now. Try again later.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "retryable": true, + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable" + } + } + ], + "failure": { + "failure_reason": "upstream_unavailable", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": null, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_queued.json b/tests/fixtures/parity/legacy/citecheck__get_queued.json new file mode 100644 index 0000000..3e7d4d1 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_queued.json @@ -0,0 +1,72 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "queued", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "poll_after_seconds": 10, + "policy": { + "max_citations": 1 + }, + "summary": { + "citations_found": 1, + "citations_selected": 1, + "citation_limit": 1, + "citation_limit_reached": false, + "citation_checks": { + "checked": 0, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "pending", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_text_limit_exactly_at_limit.json b/tests/fixtures/parity/legacy/citecheck__get_text_limit_exactly_at_limit.json new file mode 100644 index 0000000..0ff4ff1 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_text_limit_exactly_at_limit.json @@ -0,0 +1,119 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 2 + }, + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__get_text_limit_reached.json b/tests/fixtures/parity/legacy/citecheck__get_text_limit_reached.json new file mode 100644 index 0000000..764e8b1 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__get_text_limit_reached.json @@ -0,0 +1,93 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 1 + }, + "summary": { + "citations_found": 2, + "citations_selected": 1, + "citation_limit": 1, + "citation_limit_reached": true, + "citation_checks": { + "checked": 1, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0 + }, + "credits": { + "charged": 1 + }, + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_citations": [ + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "sentence": "The agency said so in a statement.", + "position": { + "start": 111, + "end": 178, + "text": null + } + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__idempotency_body_mismatch_422.json b/tests/fixtures/parity/legacy/citecheck__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..fc47586 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__idempotency_body_mismatch_422.json @@ -0,0 +1,20 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch", + "errors": [ + { + "loc": [ + "header" + ], + "msg": "Idempotency-Key reused with a different request body." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__idempotency_conflict_409.json b/tests/fixtures/parity/legacy/citecheck__idempotency_conflict_409.json new file mode 100644 index 0000000..3978a83 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__idempotency_conflict_409.json @@ -0,0 +1,13 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "A check with this Idempotency-Key is still being created. Retry shortly.", + "code": "idempotency_conflict", + "citecheck_id": null + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__idempotent_replay_202.json b/tests/fixtures/parity/legacy/citecheck__idempotent_replay_202.json new file mode 100644 index 0000000..864551e --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__idempotent_replay_202.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/citechecks/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__receipt_202.json b/tests/fixtures/parity/legacy/citecheck__receipt_202.json new file mode 100644 index 0000000..864551e --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__receipt_202.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/citechecks/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/legacy/citecheck__receipt_202_empty_webhook_url.json new file mode 100644 index 0000000..864551e --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__receipt_202_empty_webhook_url.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/citechecks/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/legacy/errors__ask_bad_language.json b/tests/fixtures/parity/legacy/errors__ask_bad_language.json new file mode 100644 index 0000000..2d6c4b1 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__ask_bad_language.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unsupported language 'xx-nope'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact." + } +} diff --git a/tests/fixtures/parity/legacy/errors__ask_empty_message.json b/tests/fixtures/parity/legacy/errors__ask_empty_message.json new file mode 100644 index 0000000..1eee180 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__ask_empty_message.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Message cannot be empty." + } +} diff --git a/tests/fixtures/parity/legacy/errors__ask_failed.json b/tests/fixtures/parity/legacy/errors__ask_failed.json new file mode 100644 index 0000000..6eb6b31 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__ask_failed.json @@ -0,0 +1,13 @@ +{ + "status": 502, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The chat model could not answer this question.", + "code": "ask_failed", + "error": "ask_failed" + } +} diff --git a/tests/fixtures/parity/legacy/errors__ask_idempotency_key_reused.json b/tests/fixtures/parity/legacy/errors__ask_idempotency_key_reused.json new file mode 100644 index 0000000..ef04562 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__ask_idempotency_key_reused.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body." + } +} diff --git a/tests/fixtures/parity/legacy/errors__ask_message_too_long.json b/tests/fixtures/parity/legacy/errors__ask_message_too_long.json new file mode 100644 index 0000000..659caed --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__ask_message_too_long.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Message too long (max 500 characters)." + } +} diff --git a/tests/fixtures/parity/legacy/errors__ask_not_completed.json b/tests/fixtures/parity/legacy/errors__ask_not_completed.json new file mode 100644 index 0000000..b59d747 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__ask_not_completed.json @@ -0,0 +1,11 @@ +{ + "status": 400, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Ask is only available for completed verifications." + } +} diff --git a/tests/fixtures/parity/legacy/errors__ask_reset_not_found.json b/tests/fixtures/parity/legacy/errors__ask_reset_not_found.json new file mode 100644 index 0000000..c0d18e1 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__ask_reset_not_found.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Verification not found." + } +} diff --git a/tests/fixtures/parity/legacy/errors__ask_send_not_found.json b/tests/fixtures/parity/legacy/errors__ask_send_not_found.json new file mode 100644 index 0000000..c0d18e1 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__ask_send_not_found.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Verification not found." + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_bad_key.json b/tests/fixtures/parity/legacy/errors__auth_bad_key.json new file mode 100644 index 0000000..8dd2fb4 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_bad_key.json @@ -0,0 +1,11 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_basic_scheme.json b/tests/fixtures/parity/legacy/errors__auth_basic_scheme.json new file mode 100644 index 0000000..8dd2fb4 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_basic_scheme.json @@ -0,0 +1,11 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_insufficient_scope.json b/tests/fixtures/parity/legacy/errors__auth_insufficient_scope.json new file mode 100644 index 0000000..15b8696 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_insufficient_scope.json @@ -0,0 +1,14 @@ +{ + "status": 403, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "WWW-Authenticate": "Bearer error=\"insufficient_scope\", scope=\"verify\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The access token does not allow this call.", + "code": "insufficient_scope", + "scope": "verify" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_missing_bearer.json b/tests/fixtures/parity/legacy/errors__auth_missing_bearer.json new file mode 100644 index 0000000..8dd2fb4 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_missing_bearer.json @@ -0,0 +1,11 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_missing_bearer_post.json b/tests/fixtures/parity/legacy/errors__auth_missing_bearer_post.json new file mode 100644 index 0000000..8dd2fb4 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_missing_bearer_post.json @@ -0,0 +1,11 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_history.json b/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_history.json new file mode 100644 index 0000000..e691e72 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_history.json @@ -0,0 +1,13 @@ +{ + "status": 403, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This report is private.", + "code": "private_claim", + "error": "private_claim" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_send.json b/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_send.json new file mode 100644 index 0000000..e691e72 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_send.json @@ -0,0 +1,13 @@ +{ + "status": 403, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This report is private.", + "code": "private_claim", + "error": "private_claim" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_unrecognised_prefix.json b/tests/fixtures/parity/legacy/errors__auth_unrecognised_prefix.json new file mode 100644 index 0000000..8dd2fb4 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_unrecognised_prefix.json @@ -0,0 +1,11 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized" + } +} diff --git a/tests/fixtures/parity/legacy/errors__http_error_library_bad_curated.json b/tests/fixtures/parity/legacy/errors__http_error_library_bad_curated.json new file mode 100644 index 0000000..03f1508 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__http_error_library_bad_curated.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Invalid curated list(s). Allowed: trivia" + } +} diff --git a/tests/fixtures/parity/legacy/errors__http_error_library_bad_verdict.json b/tests/fixtures/parity/legacy/errors__http_error_library_bad_verdict.json new file mode 100644 index 0000000..68f0346 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__http_error_library_bad_verdict.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Invalid verdict label(s). Allowed: False, Mostly False, Mixed, Mostly True, True" + } +} diff --git a/tests/fixtures/parity/legacy/errors__not_found_ask.json b/tests/fixtures/parity/legacy/errors__not_found_ask.json new file mode 100644 index 0000000..c0d18e1 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__not_found_ask.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Verification not found." + } +} diff --git a/tests/fixtures/parity/legacy/errors__not_found_route.json b/tests/fixtures/parity/legacy/errors__not_found_route.json new file mode 100644 index 0000000..06110be --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__not_found_route.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "text/html; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "": "" + } +} diff --git a/tests/fixtures/parity/legacy/errors__not_found_verification.json b/tests/fixtures/parity/legacy/errors__not_found_verification.json new file mode 100644 index 0000000..3bf3204 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__not_found_verification.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Not found." + } +} diff --git a/tests/fixtures/parity/legacy/errors__not_found_verify_status.json b/tests/fixtures/parity/legacy/errors__not_found_verify_status.json new file mode 100644 index 0000000..09c1e79 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__not_found_verify_status.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Task not found." + } +} diff --git a/tests/fixtures/parity/legacy/errors__payment_required_ask.json b/tests/fixtures/parity/legacy/errors__payment_required_ask.json new file mode 100644 index 0000000..6648329 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__payment_required_ask.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining ask credits.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/legacy/errors__payment_required_assess.json b/tests/fixtures/parity/legacy/errors__payment_required_assess.json new file mode 100644 index 0000000..1cd3038 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__payment_required_assess.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining /assess units.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/legacy/errors__payment_required_verify.json b/tests/fixtures/parity/legacy/errors__payment_required_verify.json new file mode 100644 index 0000000..32f50ac --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__payment_required_verify.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining claim checks.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 10 + } +} diff --git a/tests/fixtures/parity/legacy/errors__payment_required_verify_batch_short.json b/tests/fixtures/parity/legacy/errors__payment_required_verify_batch_short.json new file mode 100644 index 0000000..1caec0e --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__payment_required_verify_batch_short.json @@ -0,0 +1,20 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Insufficient credits for batch.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "requested": 5, + "remaining": 3, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 30, + "cost": 50 + } +} diff --git a/tests/fixtures/parity/legacy/errors__rate_limited_extract.json b/tests/fixtures/parity/legacy/errors__rate_limited_extract.json new file mode 100644 index 0000000..9e6149c --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__rate_limited_extract.json @@ -0,0 +1,17 @@ +{ + "status": 429, + "headers": { + "Content-Type": "application/json", + "Retry-After": "900", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", + "code": "extract_daily_limit", + "limit": 1000, + "reset_in_seconds": 900, + "doc_url": "https://lenz.io/docs/errors#rate-limits", + "upgrade_url": "https://lenz.io/plans" + } +} diff --git a/tests/fixtures/parity/legacy/errors__service_unavailable_ask.json b/tests/fixtures/parity/legacy/errors__service_unavailable_ask.json new file mode 100644 index 0000000..dac95ca --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__service_unavailable_ask.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The chat model is unavailable right now. Retry shortly.", + "code": "upstream_unavailable", + "retry_after": 90, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/errors__service_unavailable_capacity.json b/tests/fixtures/parity/legacy/errors__service_unavailable_capacity.json new file mode 100644 index 0000000..124f80e --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__service_unavailable_capacity.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": 60, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/errors__validation_malformed_json.json b/tests/fixtures/parity/legacy/errors__validation_malformed_json.json new file mode 100644 index 0000000..0c5de40 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__validation_malformed_json.json @@ -0,0 +1,11 @@ +{ + "status": 400, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Cannot parse request body (Expecting property name enclosed in double quotes: line 1 column 2 (char 1))" + } +} diff --git a/tests/fixtures/parity/legacy/errors__validation_missing_field_hint.json b/tests/fixtures/parity/legacy/errors__validation_missing_field_hint.json new file mode 100644 index 0000000..86c632f --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__validation_missing_field_hint.json @@ -0,0 +1,27 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "missing", + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required" + } + ], + "hint": "Required field 'text' is missing. Unrecognised fields: content, bogus.", + "doc_url": "https://lenz.io/docs/errors#validation", + "unrecognized_fields": [ + "content", + "bogus" + ] + } +} diff --git a/tests/fixtures/parity/legacy/errors__validation_unknown_field_only.json b/tests/fixtures/parity/legacy/errors__validation_unknown_field_only.json new file mode 100644 index 0000000..98527f4 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__validation_unknown_field_only.json @@ -0,0 +1,26 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "missing", + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required" + } + ], + "hint": "Required field 'claim' is missing. Unrecognised fields: statement.", + "doc_url": "https://lenz.io/docs/errors#validation", + "unrecognized_fields": [ + "statement" + ] + } +} diff --git a/tests/fixtures/parity/legacy/errors__validation_unknown_field_wrong_type.json b/tests/fixtures/parity/legacy/errors__validation_unknown_field_wrong_type.json new file mode 100644 index 0000000..643f307 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__validation_unknown_field_wrong_type.json @@ -0,0 +1,25 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "list_type", + "loc": [ + "body", + "payload", + "claims" + ], + "msg": "Input should be a valid list" + } + ], + "unrecognized_fields": [ + "bogus_field", + "another" + ] + } +} diff --git a/tests/fixtures/parity/legacy/errors__validation_wrong_type.json b/tests/fixtures/parity/legacy/errors__validation_wrong_type.json new file mode 100644 index 0000000..0c8074f --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__validation_wrong_type.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "string_type", + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Input should be a valid string" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/extract__401_no_key.json b/tests/fixtures/parity/legacy/extract__401_no_key.json new file mode 100644 index 0000000..8dd2fb4 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__401_no_key.json @@ -0,0 +1,11 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized" + } +} diff --git a/tests/fixtures/parity/legacy/extract__422_blank_text.json b/tests/fixtures/parity/legacy/extract__422_blank_text.json new file mode 100644 index 0000000..1ebb88e --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__422_blank_text.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Text is required." + } +} diff --git a/tests/fixtures/parity/legacy/extract__422_focus_too_long.json b/tests/fixtures/parity/legacy/extract__422_focus_too_long.json new file mode 100644 index 0000000..5804588 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__422_focus_too_long.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "focus must be at most 300 characters of plain text." + } +} diff --git a/tests/fixtures/parity/legacy/extract__422_missing_text.json b/tests/fixtures/parity/legacy/extract__422_missing_text.json new file mode 100644 index 0000000..9e6d6c0 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__422_missing_text.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "missing", + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/extract__429_daily_limit.json b/tests/fixtures/parity/legacy/extract__429_daily_limit.json new file mode 100644 index 0000000..729effe --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__429_daily_limit.json @@ -0,0 +1,17 @@ +{ + "status": 429, + "headers": { + "Content-Type": "application/json", + "Retry-After": "3600", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", + "code": "extract_daily_limit", + "limit": 1000, + "reset_in_seconds": 3600, + "doc_url": "https://lenz.io/docs/errors#rate-limits", + "upgrade_url": "https://lenz.io/plans" + } +} diff --git a/tests/fixtures/parity/legacy/extract__502_extraction_failed.json b/tests/fixtures/parity/legacy/extract__502_extraction_failed.json new file mode 100644 index 0000000..7deef02 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__502_extraction_failed.json @@ -0,0 +1,13 @@ +{ + "status": 502, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Extraction failed", + "code": "extraction_failed", + "error": "extraction_failed" + } +} diff --git a/tests/fixtures/parity/legacy/extract__503_upstream_unavailable.json b/tests/fixtures/parity/legacy/extract__503_upstream_unavailable.json new file mode 100644 index 0000000..b308e0c --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__503_upstream_unavailable.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Our model providers are temporarily unavailable. Please retry shortly.", + "code": "upstream_unavailable", + "retry_after": 90, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/extract__focus_ready.json b/tests/fixtures/parity/legacy/extract__focus_ready.json new file mode 100644 index 0000000..196fca1 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__focus_ready.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Beta fell 3% last year.", + "identified_claims": [], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": null + } +} diff --git a/tests/fixtures/parity/legacy/extract__idempotency_body_mismatch_422.json b/tests/fixtures/parity/legacy/extract__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..ef04562 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__idempotency_body_mismatch_422.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body." + } +} diff --git a/tests/fixtures/parity/legacy/extract__idempotency_replay.json b/tests/fixtures/parity/legacy/extract__idempotency_replay.json new file mode 100644 index 0000000..8fff1c2 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__idempotency_replay.json @@ -0,0 +1,31 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": null + } +} diff --git a/tests/fixtures/parity/legacy/extract__locate_all_dropped.json b/tests/fixtures/parity/legacy/extract__locate_all_dropped.json new file mode 100644 index 0000000..53117ce --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__locate_all_dropped.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "not_a_claim", + "claim": "", + "identified_claims": [], + "candidate_claims": [], + "domain": "", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": [] + } +} diff --git a/tests/fixtures/parity/legacy/extract__locate_failed.json b/tests/fixtures/parity/legacy/extract__locate_failed.json new file mode 100644 index 0000000..25c0403 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__locate_failed.json @@ -0,0 +1,31 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": null + } +} diff --git a/tests/fixtures/parity/legacy/extract__locate_leading_whitespace.json b/tests/fixtures/parity/legacy/extract__locate_leading_whitespace.json new file mode 100644 index 0000000..7479a3e --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__locate_leading_whitespace.json @@ -0,0 +1,39 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "start": 3, + "end": 25, + "text": "Alpha rose 5% in 2024." + } + ] + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/extract__locate_some_dropped.json b/tests/fixtures/parity/legacy/extract__locate_some_dropped.json new file mode 100644 index 0000000..6e51827 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__locate_some_dropped.json @@ -0,0 +1,52 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "start": 0, + "end": 22, + "text": "Alpha rose 5% in 2024." + } + ] + }, + { + "claim": "Beta fell 3% last year.", + "positions": [ + { + "start": 23, + "end": 46, + "text": "Beta fell 3% last year." + } + ] + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/extract__locate_true.json b/tests/fixtures/parity/legacy/extract__locate_true.json new file mode 100644 index 0000000..6e51827 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__locate_true.json @@ -0,0 +1,52 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "start": 0, + "end": 22, + "text": "Alpha rose 5% in 2024." + } + ] + }, + { + "claim": "Beta fell 3% last year.", + "positions": [ + { + "start": 23, + "end": 46, + "text": "Beta fell 3% last year." + } + ] + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/extract__no_match_with_focus.json b/tests/fixtures/parity/legacy/extract__no_match_with_focus.json new file mode 100644 index 0000000..0b34d79 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__no_match_with_focus.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "no_match", + "claim": "", + "identified_claims": [], + "candidate_claims": [], + "domain": "", + "key_entities": [], + "presumed_intent": "", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": null + } +} diff --git a/tests/fixtures/parity/legacy/extract__not_a_claim.json b/tests/fixtures/parity/legacy/extract__not_a_claim.json new file mode 100644 index 0000000..265efee --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__not_a_claim.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "not_a_claim", + "claim": "", + "identified_claims": [], + "candidate_claims": [], + "domain": "", + "key_entities": [], + "presumed_intent": "", + "original_input": "What a lovely day.", + "locations": null + } +} diff --git a/tests/fixtures/parity/legacy/extract__not_a_claim_beside_claims.json b/tests/fixtures/parity/legacy/extract__not_a_claim_beside_claims.json new file mode 100644 index 0000000..97f66d5 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__not_a_claim_beside_claims.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "not_a_claim", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024.", + "locations": null + } +} diff --git a/tests/fixtures/parity/legacy/extract__ready_one_claim.json b/tests/fixtures/parity/legacy/extract__ready_one_claim.json new file mode 100644 index 0000000..0a32c8b --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__ready_one_claim.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024.", + "locations": null + } +} diff --git a/tests/fixtures/parity/legacy/extract__ready_several_claims.json b/tests/fixtures/parity/legacy/extract__ready_several_claims.json new file mode 100644 index 0000000..25c0403 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__ready_several_claims.json @@ -0,0 +1,31 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": null + } +} diff --git a/tests/fixtures/parity/legacy/extract__replay_later_200.json b/tests/fixtures/parity/legacy/extract__replay_later_200.json new file mode 100644 index 0000000..8fff1c2 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__replay_later_200.json @@ -0,0 +1,31 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "locations": null + } +} diff --git a/tests/fixtures/parity/legacy/extract__url_fetch_502_unreadable.json b/tests/fixtures/parity/legacy/extract__url_fetch_502_unreadable.json new file mode 100644 index 0000000..7deef02 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__url_fetch_502_unreadable.json @@ -0,0 +1,13 @@ +{ + "status": 502, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Extraction failed", + "code": "extraction_failed", + "error": "extraction_failed" + } +} diff --git a/tests/fixtures/parity/legacy/extract__url_fetch_503_upstream.json b/tests/fixtures/parity/legacy/extract__url_fetch_503_upstream.json new file mode 100644 index 0000000..7cbd9f8 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__url_fetch_503_upstream.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The page could not be read right now. Please retry shortly.", + "code": "upstream_unavailable", + "retry_after": 90, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/extract__url_input_located.json b/tests/fixtures/parity/legacy/extract__url_input_located.json new file mode 100644 index 0000000..2cacb24 --- /dev/null +++ b/tests/fixtures/parity/legacy/extract__url_input_located.json @@ -0,0 +1,39 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "ready", + "claim": "Alpha rose 5% in 2024.", + "identified_claims": [], + "candidate_claims": [], + "domain": "Economics", + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "presumed_intent": "Verify reported figures", + "original_input": "https://example.com/an-article", + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "start": null, + "end": null, + "text": "Alpha rose 5% in 2024." + } + ] + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__401_no_credentials.json b/tests/fixtures/parity/legacy/review__401_no_credentials.json new file mode 100644 index 0000000..8dd2fb4 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__401_no_credentials.json @@ -0,0 +1,11 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized" + } +} diff --git a/tests/fixtures/parity/legacy/review__402_no_credits.json b/tests/fixtures/parity/legacy/review__402_no_credits.json new file mode 100644 index 0000000..c9adf9a --- /dev/null +++ b/tests/fixtures/parity/legacy/review__402_no_credits.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining credits to assess the draft.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 100, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 100, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/legacy/review__402_no_credits_exhausted.json b/tests/fixtures/parity/legacy/review__402_no_credits_exhausted.json new file mode 100644 index 0000000..cbcd2d1 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__402_no_credits_exhausted.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining credits to assess the draft.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 1 + } +} diff --git a/tests/fixtures/parity/legacy/review__422_blank_text.json b/tests/fixtures/parity/legacy/review__422_blank_text.json new file mode 100644 index 0000000..b820499 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_blank_text.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "text: send the draft, or one public http(s) URL.", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "text" + ], + "msg": "text: send the draft, or one public http(s) URL." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_citations_options_object.json b/tests/fixtures/parity/legacy/review__422_citations_options_object.json new file mode 100644 index 0000000..1f3923f --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_citations_options_object.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.citations: Extra inputs are not permitted", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "citations" + ], + "msg": "Extra inputs are not permitted" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_depth_unknown.json b/tests/fixtures/parity/legacy/review__422_depth_unknown.json new file mode 100644 index 0000000..dcce2ae --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_depth_unknown.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.escalate.depth: Input should be 'standard' or 'low'", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "depth" + ], + "msg": "Input should be 'standard' or 'low'" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_invalid_confidence_band.json b/tests/fixtures/parity/legacy/review__422_invalid_confidence_band.json new file mode 100644 index 0000000..8dccb97 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_invalid_confidence_band.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.escalate.confidence: Unknown confidence band 'certain'; use low, medium or high.", + "code": "invalid_confidence_band", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "confidence" + ], + "msg": "Unknown confidence band 'certain'; use low, medium or high." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_invalid_verdict_label.json b/tests/fixtures/parity/legacy/review__422_invalid_verdict_label.json new file mode 100644 index 0000000..40f409f --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_invalid_verdict_label.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.escalate.verdicts: Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True.", + "code": "invalid_verdict_label", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "verdicts" + ], + "msg": "Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_max_assessments_negative.json b/tests/fixtures/parity/legacy/review__422_max_assessments_negative.json new file mode 100644 index 0000000..c88a65e --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_max_assessments_negative.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.escalate.max_assessments: Input should be greater than or equal to 0", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_assessments" + ], + "msg": "Input should be greater than or equal to 0" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_max_citations_negative.json b/tests/fixtures/parity/legacy/review__422_max_citations_negative.json new file mode 100644 index 0000000..13e166c --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_max_citations_negative.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.escalate.max_citations: Input should be greater than or equal to 0", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_citations" + ], + "msg": "Input should be greater than or equal to 0" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_max_citations_too_big.json b/tests/fixtures/parity/legacy/review__422_max_citations_too_big.json new file mode 100644 index 0000000..10fcf2c --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_max_citations_too_big.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.escalate.max_citations: Input should be less than or equal to 20", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_citations" + ], + "msg": "Input should be less than or equal to 20" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_max_verifications_too_big.json b/tests/fixtures/parity/legacy/review__422_max_verifications_too_big.json new file mode 100644 index 0000000..9c2e2eb --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_max_verifications_too_big.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.escalate.max_verifications: Input should be less than or equal to 20", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "max_verifications" + ], + "msg": "Input should be less than or equal to 20" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_text_missing.json b/tests/fixtures/parity/legacy/review__422_text_missing.json new file mode 100644 index 0000000..de972a9 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_text_missing.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.text: Field required", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_text_wrong_type.json b/tests/fixtures/parity/legacy/review__422_text_wrong_type.json new file mode 100644 index 0000000..2638c63 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_text_wrong_type.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.text: Input should be a valid string", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Input should be a valid string" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_unknown_escalate_field.json b/tests/fixtures/parity/legacy/review__422_unknown_escalate_field.json new file mode 100644 index 0000000..2c5c7e9 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_unknown_escalate_field.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.escalate.nope: Extra inputs are not permitted", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "escalate", + "nope" + ], + "msg": "Extra inputs are not permitted" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_unknown_top_level_field.json b/tests/fixtures/parity/legacy/review__422_unknown_top_level_field.json new file mode 100644 index 0000000..f91e1f3 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_unknown_top_level_field.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.max_verifications: Extra inputs are not permitted", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "max_verifications" + ], + "msg": "Extra inputs are not permitted" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_unsupported_language.json b/tests/fixtures/parity/legacy/review__422_unsupported_language.json new file mode 100644 index 0000000..26f0a19 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_unsupported_language.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "language: Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "language" + ], + "msg": "language: Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__422_visibility_public.json b/tests/fixtures/parity/legacy/review__422_visibility_public.json new file mode 100644 index 0000000..3c72623 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_visibility_public.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "payload.visibility: Input should be 'private' or 'unlisted'", + "code": "validation_error", + "errors": [ + { + "loc": [ + "body", + "payload", + "visibility" + ], + "msg": "Input should be 'private' or 'unlisted'" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__429_extract_daily_limit.json b/tests/fixtures/parity/legacy/review__429_extract_daily_limit.json new file mode 100644 index 0000000..f7f182a --- /dev/null +++ b/tests/fixtures/parity/legacy/review__429_extract_daily_limit.json @@ -0,0 +1,17 @@ +{ + "status": 429, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Daily /extract limit of 1000 reached for this account. A review of a URL reads the page like /extract and counts as one /extract call.", + "code": "extract_daily_limit", + "limit": 1000, + "reset_in_seconds": 60, + "doc_url": "https://lenz.io/docs/errors#rate-limits", + "upgrade_url": "https://lenz.io/plans" + } +} diff --git a/tests/fixtures/parity/legacy/review__429_review_in_flight.json b/tests/fixtures/parity/legacy/review__429_review_in_flight.json new file mode 100644 index 0000000..c8777a5 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__429_review_in_flight.json @@ -0,0 +1,14 @@ +{ + "status": 429, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This account already has 3 reviews running. Retry when one completes.", + "code": "review_in_flight", + "retry_after_seconds": 60 + } +} diff --git a/tests/fixtures/parity/legacy/review__503_capacity.json b/tests/fixtures/parity/legacy/review__503_capacity.json new file mode 100644 index 0000000..adcc209 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__503_capacity.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": 90, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/review__503_citations_capacity.json b/tests/fixtures/parity/legacy/review__503_citations_capacity.json new file mode 100644 index 0000000..adcc209 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__503_citations_capacity.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": 90, + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/review__get_403_insufficient_scope.json b/tests/fixtures/parity/legacy/review__get_403_insufficient_scope.json new file mode 100644 index 0000000..80c529c --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_403_insufficient_scope.json @@ -0,0 +1,14 @@ +{ + "status": 403, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "WWW-Authenticate": "Bearer error=\"insufficient_scope\", scope=\"history:read\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "The access token does not allow this call.", + "code": "insufficient_scope", + "scope": "history:read" + } +} diff --git a/tests/fixtures/parity/legacy/review__get_404_not_found.json b/tests/fixtures/parity/legacy/review__get_404_not_found.json new file mode 100644 index 0000000..8045cd8 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_404_not_found.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Review not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/legacy/review__get_404_other_account.json b/tests/fixtures/parity/legacy/review__get_404_other_account.json new file mode 100644 index 0000000..8045cd8 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_404_other_account.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Review not found.", + "code": "not_found" + } +} diff --git a/tests/fixtures/parity/legacy/review__get_410_purged.json b/tests/fixtures/parity/legacy/review__get_410_purged.json new file mode 100644 index 0000000..bedf6a5 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_410_purged.json @@ -0,0 +1,13 @@ +{ + "status": 410, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This review is no longer available: its account removes content after a set period.", + "code": "purged", + "purged_at": "2026-10-01T09:07:00.123456Z" + } +} diff --git a/tests/fixtures/parity/legacy/review__get_422_unknown_view.json b/tests/fixtures/parity/legacy/review__get_422_unknown_view.json new file mode 100644 index 0000000..531cbd7 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_422_unknown_view.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "view: use full or issues.", + "code": "validation_error", + "errors": [ + { + "loc": [ + "query", + "view" + ], + "msg": "view: use full or issues." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_assessing.json b/tests/fixtures/parity/legacy/review__get_assessing.json new file mode 100644 index 0000000..eff0c0d --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_assessing.json @@ -0,0 +1,110 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "assessing", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 0, + "failed": 0 + }, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": 10, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": null, + "assessment": { + "status": "running", + "verdict": null, + "confidence": null, + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": null, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": null, + "assessment": { + "status": "running", + "verdict": null, + "confidence": null, + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": null, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_assessment_rows_full_fields.json b/tests/fixtures/parity/legacy/review__get_assessment_rows_full_fields.json new file mode 100644 index 0000000..c7b40ba --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_assessment_rows_full_fields.json @@ -0,0 +1,170 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 0, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 1 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": null, + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "cap" + }, + "key_finding": null, + "rationale": "Two reviewers found the date wrong.", + "suggested_rewrite": "The EU AI Act entered into force in August 2024.", + "failure": null, + "suggested_edits": null + } + ], + "failures": [ + { + "claim_index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "stage": "assessment", + "failure": { + "failure_reason": "timeout", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": "The check ran out of time. Retry it; nothing was charged.", + "docs_url": null + } + } + ], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "assessment", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": "Two reviewers found the date wrong.", + "dissent": "One reviewer read the claim as about the entry into force.", + "verification_url": null, + "error_code": null, + "identified_claims": [ + "The EU AI Act took effect in 2024.", + "It took effect in March." + ], + "hint": "This text holds more than one claim.", + "suggested_rewrite": "The EU AI Act entered into force in August 2024.", + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "cap" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": null, + "assessment": { + "status": "failed", + "verdict": null, + "confidence": null, + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": "timeout", + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": { + "failure_reason": "timeout", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": "The check ran out of time. Retry it; nothing was charged.", + "docs_url": null + } + }, + "escalation": null, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_clean.json b/tests/fixtures/parity/legacy/review__get_citations_clean.json new file mode 100644 index 0000000..c4bb6cc --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_clean.json @@ -0,0 +1,183 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 3 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_failed_and_unchecked.json b/tests/fixtures/parity/legacy/review__get_citations_failed_and_unchecked.json new file mode 100644 index 0000000..39737a0 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_failed_and_unchecked.json @@ -0,0 +1,199 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_reached": false, + "citation_checks": { + "checked": 0, + "unchecked": 1, + "failed": 1 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [ + { + "citation_index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": { + "hint": "The check failed on our side. Try again later.", + "docs_url": "https://lenz.io/docs/errors#internal", + "retryable": false, + "failure_class": "internal", + "failure_reason": "internal" + } + } + ], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": null, + "check": { + "status": "failed", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": "The check failed on our side. Try again later.", + "failure": { + "hint": "The check failed on our side. Try again later.", + "docs_url": "https://lenz.io/docs/errors#internal", + "retryable": false, + "failure_class": "internal", + "failure_reason": "internal" + }, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "unchecked", + "source": null, + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "unchecked", + "snippet": null, + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": "no_text", + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_issue_full.json b/tests/fixtures/parity/legacy/review__get_citations_issue_full.json new file mode 100644 index 0000000..df60b05 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_issue_full.json @@ -0,0 +1,205 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 1, + "citations_skipped": null + }, + "credits": { + "charged": 3 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [ + { + "citation_index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "finding": "contradicted", + "source": "support", + "snippet": "The source says so.", + "rationale": "The page states it.", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "failure": null + } + ], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "contradicted", + "source": "support", + "is_issue": true + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "contradicted", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_issue_issues_view.json b/tests/fixtures/parity/legacy/review__get_citations_issue_issues_view.json new file mode 100644 index 0000000..c8414d9 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_issue_issues_view.json @@ -0,0 +1,93 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "issues", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 1, + "citations_skipped": null + }, + "credits": { + "charged": 3 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [ + { + "citation_index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "finding": "contradicted", + "source": "support", + "snippet": "The source says so.", + "rationale": "The page states it.", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "failure": null + } + ], + "citation_failures": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_limit_exactly_at_limit.json b/tests/fixtures/parity/legacy/review__get_citations_limit_exactly_at_limit.json new file mode 100644 index 0000000..9d9e9d7 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_limit_exactly_at_limit.json @@ -0,0 +1,183 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 2, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 3 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_limit_reached.json b/tests/fixtures/parity/legacy/review__get_citations_limit_reached.json new file mode 100644 index 0000000..570c334 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_limit_reached.json @@ -0,0 +1,157 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 1, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 1, + "citation_limit": 1, + "citation_limit_reached": true, + "citation_checks": { + "checked": 1, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [ + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "sentence": "The agency said so in a statement.", + "position": { + "start": 111, + "end": 178, + "text": null + } + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_no_claim_but_citations.json b/tests/fixtures/parity/legacy/review__get_citations_no_claim_but_citations.json new file mode 100644 index 0000000..5c19752 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_no_claim_but_citations.json @@ -0,0 +1,152 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": 0, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 0, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_no_claim_no_citation.json b/tests/fixtures/parity/legacy/review__get_citations_no_claim_no_citation.json new file mode 100644 index 0000000..c588505 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_no_claim_no_citation.json @@ -0,0 +1,68 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": null, + "claim_limit": 20, + "claim_limit_reached": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": 20, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": { + "failure_reason": "no_claim", + "failure_class": "invalid_input", + "retryable": false, + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_not_asked.json b/tests/fixtures/parity/legacy/review__get_citations_not_asked.json new file mode 100644 index 0000000..386fe10 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_not_asked.json @@ -0,0 +1,100 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_only.json b/tests/fixtures/parity/legacy/review__get_citations_only.json new file mode 100644 index 0000000..287e33e --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_only.json @@ -0,0 +1,159 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 0, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": 0, + "claim_limit": 0, + "claim_limit_reached": true, + "input_truncated": false, + "assessments": { + "completed": 0, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [ + "The EU AI Act took effect in March 2024." + ], + "more_claim_locations": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "positions": null + } + ], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_partly_supported.json b/tests/fixtures/parity/legacy/review__get_citations_partly_supported.json new file mode 100644 index 0000000..6c96719 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_partly_supported.json @@ -0,0 +1,183 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 3 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry.", + "quotes": [], + "position": { + "start": 0, + "end": 110, + "text": null + }, + "result": { + "finding": "partly_supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "partly_supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": { + "start": 111, + "end": 178, + "text": null + }, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_running.json b/tests/fixtures/parity/legacy/review__get_citations_running.json new file mode 100644 index 0000000..e72b98c --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_running.json @@ -0,0 +1,167 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "verifying", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 20, + "citation_limit_reached": false, + "citation_checks": { + "checked": 0, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": 15, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [ + { + "index": 0, + "reference": "a report from the ministry", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": null, + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "pending", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "a statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": null, + "quotes": [], + "position": null, + "result": null, + "check": { + "status": "pending", + "page_read": null, + "page_title": null, + "page_published_date": null, + "page_language": null, + "source_url": null, + "source_version": null, + "support": null, + "snippet": null, + "rationale": null, + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_skipped_switched_off.json b/tests/fixtures/parity/legacy/review__get_citations_skipped_switched_off.json new file mode 100644 index 0000000..b67e879 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_skipped_switched_off.json @@ -0,0 +1,100 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": 20, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": "switched_off" + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_citations_skipped_url_input.json b/tests/fixtures/parity/legacy/review__get_citations_skipped_url_input.json new file mode 100644 index 0000000..04d13c0 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_citations_skipped_url_input.json @@ -0,0 +1,68 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 20, + "suggest_edits": false + }, + "summary": { + "claims_selected": null, + "claim_limit": 20, + "claim_limit_reached": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": 20, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": "url_input" + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": { + "failure_reason": "upstream_unavailable", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": null, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/legacy/review__get_claim_limit_not_reached.json b/tests/fixtures/parity/legacy/review__get_claim_limit_not_reached.json new file mode 100644 index 0000000..97b6112 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_claim_limit_not_reached.json @@ -0,0 +1,130 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 3, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 3, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_claim_limit_reached_exact.json b/tests/fixtures/parity/legacy/review__get_claim_limit_reached_exact.json new file mode 100644 index 0000000..55d5182 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_claim_limit_reached_exact.json @@ -0,0 +1,130 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 2, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 2, + "claim_limit_reached": true, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_completed_assess_only.json b/tests/fixtures/parity/legacy/review__get_completed_assess_only.json new file mode 100644 index 0000000..ff8ce84 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_completed_assess_only.json @@ -0,0 +1,156 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 0, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": null, + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "cap" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "assessment", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "cap" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_completed_clean.json b/tests/fixtures/parity/legacy/review__get_completed_clean.json new file mode 100644 index 0000000..3f2020c --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_completed_clean.json @@ -0,0 +1,130 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Paris is the capital of France.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_completed_issues_all_verified.json b/tests/fixtures/parity/legacy/review__get_completed_issues_all_verified.json new file mode 100644 index 0000000..81957e3 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_completed_issues_all_verified.json @@ -0,0 +1,261 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 3, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 3, + "failed": 0 + }, + "verifications": { + "planned": 2, + "completed": 2, + "failed": 0 + }, + "issues": 2, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 23 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "failure": null, + "suggested_edits": null + }, + { + "claim_index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b79019e4", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", + "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "Mostly False", + "confidence": "medium", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "c010dca9a43543f518e49f4ec7842ceb", + "verification_id": "b4e2e99d", + "claim": "The EU AI Act took effect in March 2024.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "executive_summary": "Summary for The EU AI Act took effect in March 2024.", + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T09:49:00.123456+00:00", + "modified_at": null, + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "failure": null + }, + "suggested_edits": null + }, + { + "index": 1, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "4634b89821fd877f1edf8aaeb82b7ee5", + "verification_id": "b79019e4", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T09:49:00.123456+00:00", + "modified_at": null, + "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", + "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "failure": null + }, + "suggested_edits": null + }, + { + "index": 2, + "claim": "Paris is the capital of France.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_completed_issues_full.json b/tests/fixtures/parity/legacy/review__get_completed_issues_full.json new file mode 100644 index 0000000..a8c7245 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_completed_issues_full.json @@ -0,0 +1,312 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 4, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 3, + "failed": 1 + }, + "verifications": { + "planned": 2, + "completed": 1, + "failed": 1 + }, + "issues": 2, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 13 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "failure": null, + "suggested_edits": null + }, + { + "claim_index": 2, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": "failed", + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": { + "failure_reason": "research_empty", + "failure_class": "insufficient_evidence", + "retryable": false, + "hint": null, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + }, + "suggested_edits": null + } + ], + "failures": [ + { + "claim_index": 1, + "claim": "Water boils at 100 C at sea level.", + "stage": "assessment", + "failure": { + "failure_reason": "upstream_unavailable", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + } + ], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "Mostly False", + "confidence": "medium", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "7df4009bc27aab64ce5d5a01fbafe599", + "verification_id": "b4e2e99d", + "claim": "The EU AI Act took effect in March 2024.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "executive_summary": "Summary for The EU AI Act took effect in March 2024.", + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T09:42:00.123456+00:00", + "modified_at": null, + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "failure": null + }, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": null, + "assessment": { + "status": "failed", + "verdict": null, + "confidence": null, + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": "upstream_unavailable", + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": { + "failure_reason": "upstream_unavailable", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + }, + "escalation": null, + "verification": null, + "suggested_edits": null + }, + { + "index": 2, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "assessment", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "verification_id": null, + "task_id": "5ccac77f53ff49328ec134fb29d66542", + "claim": null, + "language": null, + "visibility": null, + "depth": null, + "domain": null, + "entities": [], + "verdict": null, + "confidence": null, + "lenz_score": null, + "key_finding": null, + "executive_summary": null, + "suggested_rewrite": null, + "warnings": [], + "created_at": null, + "modified_at": null, + "verification_url": null, + "url": null, + "failure": { + "failure_reason": "research_empty", + "failure_class": "insufficient_evidence", + "retryable": false, + "hint": null, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + }, + "status": "failed", + "content_status": "available" + }, + "suggested_edits": null + }, + { + "index": 3, + "claim": "Paris is the capital of France.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_completed_issues_view_issues.json b/tests/fixtures/parity/legacy/review__get_completed_issues_view_issues.json new file mode 100644 index 0000000..c42387e --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_completed_issues_view_issues.json @@ -0,0 +1,133 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "issues", + "status": "completed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 4, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 3, + "failed": 1 + }, + "verifications": { + "planned": 2, + "completed": 1, + "failed": 1 + }, + "issues": 2, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 13 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "failure": null, + "suggested_edits": null + }, + { + "claim_index": 2, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": "failed", + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": { + "failure_reason": "research_empty", + "failure_class": "insufficient_evidence", + "retryable": false, + "hint": null, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + }, + "suggested_edits": null + } + ], + "failures": [ + { + "claim_index": 1, + "claim": "Water boils at 100 C at sea level.", + "stage": "assessment", + "failure": { + "failure_reason": "upstream_unavailable", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + } + ], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_completed_positions.json b/tests/fixtures/parity/legacy/review__get_completed_positions.json new file mode 100644 index 0000000..85f1f60 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_completed_positions.json @@ -0,0 +1,142 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": [ + { + "start": 0, + "end": 40, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": [ + { + "start": 55, + "end": 89, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_completed_recovered_claim.json b/tests/fixtures/parity/legacy/review__get_completed_recovered_claim.json new file mode 100644 index 0000000..9bba88a --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_completed_recovered_claim.json @@ -0,0 +1,100 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "Orbit Motors stock increased by 40% in 2022.", + "positions": [], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_completed_with_untraced_claim.json b/tests/fixtures/parity/legacy/review__get_completed_with_untraced_claim.json new file mode 100644 index 0000000..c58b50b --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_completed_with_untraced_claim.json @@ -0,0 +1,142 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": [ + { + "start": 0, + "end": 40, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": [ + { + "start": 50, + "end": 84, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_during_quick_check.json b/tests/fixtures/parity/legacy/review__get_during_quick_check.json new file mode 100644 index 0000000..7b3787b --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_during_quick_check.json @@ -0,0 +1,88 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "assessing", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 0, + "failed": 0 + }, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": 10, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": null, + "assessment": { + "status": "running", + "verdict": null, + "confidence": null, + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": null, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_failed_every_assessment_failed.json b/tests/fixtures/parity/legacy/review__get_failed_every_assessment_failed.json new file mode 100644 index 0000000..12698ba --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_failed_every_assessment_failed.json @@ -0,0 +1,157 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "failed", + "outcome": "incomplete", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 0, + "failed": 2 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "stage": "assessment", + "failure": { + "failure_reason": "upstream_unavailable", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + }, + { + "claim_index": 1, + "claim": "Water boils at 100 C at sea level.", + "stage": "assessment", + "failure": { + "failure_reason": "upstream_unavailable", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + } + ], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": null, + "assessment": { + "status": "failed", + "verdict": null, + "confidence": null, + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": "upstream_unavailable", + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": { + "failure_reason": "upstream_unavailable", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + }, + "escalation": null, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": null, + "assessment": { + "status": "failed", + "verdict": null, + "confidence": null, + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": "upstream_unavailable", + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": { + "failure_reason": "upstream_unavailable", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } + }, + "escalation": null, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": { + "failure_reason": "assessment_failed", + "failure_class": "upstream_unavailable", + "retryable": true, + "hint": "No claim could be assessed. Retry the review with a new Idempotency-Key; nothing was charged.", + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_failed_no_claim.json b/tests/fixtures/parity/legacy/review__get_failed_no_claim.json new file mode 100644 index 0000000..5d5200a --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_failed_no_claim.json @@ -0,0 +1,68 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": null, + "claim_limit": 20, + "claim_limit_reached": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": { + "failure_reason": "no_claim", + "failure_class": "invalid_input", + "retryable": false, + "hint": "The text is a greeting, not a statement about the world. Send one factual claim, or run the text through /extract to enumerate its claims.", + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/legacy/review__get_failed_no_claim_untraced.json b/tests/fixtures/parity/legacy/review__get_failed_no_claim_untraced.json new file mode 100644 index 0000000..823468b --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_failed_no_claim_untraced.json @@ -0,0 +1,68 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": null, + "claim_limit": 20, + "claim_limit_reached": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": { + "failure_reason": "no_claim", + "failure_class": "invalid_input", + "retryable": false, + "hint": "None of the claims found in the text could be traced back to it. Send one factual claim, or run the text through /extract to enumerate its claims.", + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/legacy/review__get_more_claims.json b/tests/fixtures/parity/legacy/review__get_more_claims.json new file mode 100644 index 0000000..5f268da --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_more_claims.json @@ -0,0 +1,155 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 2, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 2, + "claim_limit_reached": true, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": [ + { + "start": 0, + "end": 40, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": [ + { + "start": 50, + "end": 84, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [ + "The Eiffel Tower is in Berlin." + ], + "more_claim_locations": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "positions": [ + { + "start": 91, + "end": 121, + "text": "The Eiffel Tower is in Berlin." + } + ] + } + ], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..52e321f --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,151 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 1, + "completed": 1, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 11 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "7df4009bc27aab64ce5d5a01fbafe599", + "verification_id": "b4e2e99d", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T23:55:00.123456+00:00", + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "failure": null + }, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..9054ce3 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_same_day_hours_apart.json @@ -0,0 +1,151 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 1, + "completed": 1, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 11 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "b4e2e99d", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "7df4009bc27aab64ce5d5a01fbafe599", + "verification_id": "b4e2e99d", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T08:00:00.123456+00:00", + "modified_at": null, + "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "failure": null + }, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_policy_resolved.json b/tests/fixtures/parity/legacy/review__get_policy_resolved.json new file mode 100644 index 0000000..3116b84 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_policy_resolved.json @@ -0,0 +1,98 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 2, + "depth": "low", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_queued.json b/tests/fixtures/parity/legacy/review__get_queued.json new file mode 100644 index 0000000..306403b --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_queued.json @@ -0,0 +1,62 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "queued", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": null, + "claim_limit": 20, + "claim_limit_reached": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": 10, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": null, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + } +} diff --git a/tests/fixtures/parity/legacy/review__get_suggested_edits.json b/tests/fixtures/parity/legacy/review__get_suggested_edits.json new file mode 100644 index 0000000..aba4758 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_suggested_edits.json @@ -0,0 +1,269 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "verifying", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "suggest_edits": true, + "max_citations": 0 + }, + "summary": { + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 2, + "completed": 1, + "failed": 0 + }, + "issues": 2, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 12 + }, + "poll_after_seconds": 15, + "issues": [ + { + "claim_index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "7c83247c", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": { + "status": "completed", + "edits": [ + { + "position": 0, + "start": 23, + "end": 29, + "text": "Berlin", + "replacement": "Paris" + } + ] + } + }, + { + "claim_index": 1, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": null, + "suggested_edits": { + "status": "pending", + "edits": null + } + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "positions": [ + { + "start": 0, + "end": 30, + "text": "The Eiffel Tower is in Berlin." + } + ], + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "9bca1e0819de60a750186e812dc58e2b", + "verification_id": "7c83247c", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T09:35:00.123456+00:00", + "modified_at": null, + "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "failure": null + }, + "suggested_edits": { + "status": "completed", + "edits": [ + { + "position": 0, + "start": 23, + "end": 29, + "text": "Berlin", + "replacement": "Paris" + } + ] + } + }, + { + "index": 1, + "claim": "The EU AI Act took effect in March 2024.", + "positions": [ + { + "start": 45, + "end": 85, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "verdict": "False", + "confidence": "high", + "source": "assessment", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "processing", + "content_status": "available", + "verification_id": null, + "task_id": null, + "claim": null, + "language": null, + "visibility": null, + "depth": null, + "domain": null, + "entities": [], + "verdict": null, + "confidence": null, + "lenz_score": null, + "key_finding": null, + "executive_summary": null, + "suggested_rewrite": null, + "warnings": [], + "created_at": null, + "modified_at": null, + "verification_url": null, + "url": null, + "failure": null + }, + "suggested_edits": { + "status": "pending", + "edits": null + } + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_suggested_edits_issues_view.json b/tests/fixtures/parity/legacy/review__get_suggested_edits_issues_view.json new file mode 100644 index 0000000..1ffd8c0 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_suggested_edits_issues_view.json @@ -0,0 +1,128 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "issues", + "status": "verifying", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "suggest_edits": true, + "max_citations": 0 + }, + "summary": { + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 2, + "completed": 1, + "failed": 0 + }, + "issues": 2, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 12 + }, + "poll_after_seconds": 15, + "issues": [ + { + "claim_index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "7c83247c", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": { + "status": "completed", + "edits": [ + { + "position": 0, + "start": 23, + "end": 29, + "text": "Berlin", + "replacement": "Paris" + } + ] + } + }, + { + "claim_index": 1, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": null, + "suggested_edits": { + "status": "pending", + "edits": null + } + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_url_review.json b/tests/fixtures/parity/legacy/review__get_url_review.json new file mode 100644 index 0000000..ca8ddf6 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_url_review.json @@ -0,0 +1,106 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T09:21:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": [ + { + "start": null, + "end": null, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__get_verifying.json b/tests/fixtures/parity/legacy/review__get_verifying.json new file mode 100644 index 0000000..a388043 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__get_verifying.json @@ -0,0 +1,179 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "view": "full", + "status": "verifying", + "outcome": null, + "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": null, + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 2, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 2, + "failed": 0 + }, + "verifications": { + "planned": 1, + "completed": 0, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 2 + }, + "poll_after_seconds": 15, + "issues": [ + { + "claim_index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "assessment", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "url": null, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": null, + "rationale": null, + "suggested_rewrite": null, + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The EU AI Act took effect in March 2024.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "assessment", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "processing", + "content_status": "available", + "verification_id": null, + "task_id": null, + "claim": null, + "language": null, + "visibility": null, + "depth": null, + "domain": null, + "entities": [], + "verdict": null, + "confidence": null, + "lenz_score": null, + "key_finding": null, + "executive_summary": null, + "suggested_rewrite": null, + "warnings": [], + "created_at": null, + "modified_at": null, + "verification_url": null, + "url": null, + "failure": null + }, + "suggested_edits": null + }, + { + "index": 1, + "claim": "Water boils at 100 C at sea level.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + } +} diff --git a/tests/fixtures/parity/legacy/review__idempotency_body_mismatch_422.json b/tests/fixtures/parity/legacy/review__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..fc47586 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__idempotency_body_mismatch_422.json @@ -0,0 +1,20 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch", + "errors": [ + { + "loc": [ + "header" + ], + "msg": "Idempotency-Key reused with a different request body." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/review__idempotency_conflict_409.json b/tests/fixtures/parity/legacy/review__idempotency_conflict_409.json new file mode 100644 index 0000000..8bbdff7 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__idempotency_conflict_409.json @@ -0,0 +1,13 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "A review with this Idempotency-Key is still being created. Retry shortly.", + "code": "idempotency_conflict", + "review_id": null + } +} diff --git a/tests/fixtures/parity/legacy/review__idempotency_conflict_409_existing_review.json b/tests/fixtures/parity/legacy/review__idempotency_conflict_409_existing_review.json new file mode 100644 index 0000000..edef440 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__idempotency_conflict_409_existing_review.json @@ -0,0 +1,13 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "A review with this Idempotency-Key is still being created. Retry shortly.", + "code": "idempotency_conflict", + "review_id": "d6b2bd72" + } +} diff --git a/tests/fixtures/parity/legacy/review__idempotent_replay_202.json b/tests/fixtures/parity/legacy/review__idempotent_replay_202.json new file mode 100644 index 0000000..6a0872b --- /dev/null +++ b/tests/fixtures/parity/legacy/review__idempotent_replay_202.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/reviews/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/legacy/review__receipt_202.json b/tests/fixtures/parity/legacy/review__receipt_202.json new file mode 100644 index 0000000..6a0872b --- /dev/null +++ b/tests/fixtures/parity/legacy/review__receipt_202.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/reviews/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/legacy/review__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/legacy/review__receipt_202_empty_webhook_url.json new file mode 100644 index 0000000..6a0872b --- /dev/null +++ b/tests/fixtures/parity/legacy/review__receipt_202_empty_webhook_url.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/reviews/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/legacy/review__receipt_202_webhook_url.json b/tests/fixtures/parity/legacy/review__receipt_202_webhook_url.json new file mode 100644 index 0000000..6a0872b --- /dev/null +++ b/tests/fixtures/parity/legacy/review__receipt_202_webhook_url.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/reviews/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/legacy/review__replay_later_202.json b/tests/fixtures/parity/legacy/review__replay_later_202.json new file mode 100644 index 0000000..6a0872b --- /dev/null +++ b/tests/fixtures/parity/legacy/review__replay_later_202.json @@ -0,0 +1,14 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Retry-After": "20", + "Location": "/api/v1/reviews/d6b2bd72", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/legacy/verify__batch_202.json b/tests/fixtures/parity/legacy/verify__batch_202.json new file mode 100644 index 0000000..7229ce4 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__batch_202.json @@ -0,0 +1,21 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "claim_text": "The Earth is round." + }, + { + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "claim_text": "Water boils at 100C at sea level." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/verify__batch_capacity_503.json b/tests/fixtures/parity/legacy/verify__batch_capacity_503.json new file mode 100644 index 0000000..342c8aa --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__batch_capacity_503.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": "", + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/verify__batch_empty_422.json b/tests/fixtures/parity/legacy/verify__batch_empty_422.json new file mode 100644 index 0000000..48a686f --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__batch_empty_422.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "claims is required and must be non-empty." + } +} diff --git a/tests/fixtures/parity/legacy/verify__batch_idempotency_conflict_409.json b/tests/fixtures/parity/legacy/verify__batch_idempotency_conflict_409.json new file mode 100644 index 0000000..0b70d8c --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__batch_idempotency_conflict_409.json @@ -0,0 +1,12 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "A request with this Idempotency-Key is already in progress.", + "task_id": "7cff18d" + } +} diff --git a/tests/fixtures/parity/legacy/verify__batch_item_missing_claim_422.json b/tests/fixtures/parity/legacy/verify__batch_item_missing_claim_422.json new file mode 100644 index 0000000..ad1fc01 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__batch_item_missing_claim_422.json @@ -0,0 +1,23 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "missing", + "loc": [ + "body", + "payload", + "claims", + 1, + "text" + ], + "msg": "Field required" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/verify__batch_no_credits_402.json b/tests/fixtures/parity/legacy/verify__batch_no_credits_402.json new file mode 100644 index 0000000..5ec2c08 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__batch_no_credits_402.json @@ -0,0 +1,20 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Insufficient credits for batch.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "requested": 1, + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 10 + } +} diff --git a/tests/fixtures/parity/legacy/verify__batch_partial_202.json b/tests/fixtures/parity/legacy/verify__batch_partial_202.json new file mode 100644 index 0000000..5bfc144 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__batch_partial_202.json @@ -0,0 +1,18 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "claim_text": "First claim." + } + ], + "partial": true + } +} diff --git a/tests/fixtures/parity/legacy/verify__batch_too_many_422.json b/tests/fixtures/parity/legacy/verify__batch_too_many_422.json new file mode 100644 index 0000000..a865749 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__batch_too_many_422.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Batch size exceeds maximum of 20." + } +} diff --git a/tests/fixtures/parity/legacy/verify__blank_claim_422.json b/tests/fixtures/parity/legacy/verify__blank_claim_422.json new file mode 100644 index 0000000..1ebb88e --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__blank_claim_422.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Text is required." + } +} diff --git a/tests/fixtures/parity/legacy/verify__capacity_503.json b/tests/fixtures/parity/legacy/verify__capacity_503.json new file mode 100644 index 0000000..342c8aa --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__capacity_503.json @@ -0,0 +1,15 @@ +{ + "status": 503, + "headers": { + "Content-Type": "application/json", + "Retry-After": "", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", + "code": "capacity", + "retry_after": "", + "doc_url": "https://lenz.io/docs/errors#unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/verify__idempotency_body_mismatch_422.json b/tests/fixtures/parity/legacy/verify__idempotency_body_mismatch_422.json new file mode 100644 index 0000000..ef04562 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__idempotency_body_mismatch_422.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Idempotency-Key reused with a different request body." + } +} diff --git a/tests/fixtures/parity/legacy/verify__idempotency_conflict_409.json b/tests/fixtures/parity/legacy/verify__idempotency_conflict_409.json new file mode 100644 index 0000000..0eee4f9 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__idempotency_conflict_409.json @@ -0,0 +1,12 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "A request with this Idempotency-Key is already in progress.", + "task_id": "7cff18da2d979d6370e54a160be121ad" + } +} diff --git a/tests/fixtures/parity/legacy/verify__idempotency_key_replay.json b/tests/fixtures/parity/legacy/verify__idempotency_key_replay.json new file mode 100644 index 0000000..b6dbf5e --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__idempotency_key_replay.json @@ -0,0 +1,13 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "78ac4e9f234ea3bd" + } +} diff --git a/tests/fixtures/parity/legacy/verify__implicit_dedup_200.json b/tests/fixtures/parity/legacy/verify__implicit_dedup_200.json new file mode 100644 index 0000000..011b4b9 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__implicit_dedup_200.json @@ -0,0 +1,12 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + } +} diff --git a/tests/fixtures/parity/legacy/verify__implicit_repeat_replay.json b/tests/fixtures/parity/legacy/verify__implicit_repeat_replay.json new file mode 100644 index 0000000..b6dbf5e --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__implicit_repeat_replay.json @@ -0,0 +1,13 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "78ac4e9f234ea3bd" + } +} diff --git a/tests/fixtures/parity/legacy/verify__invalid_depth_422.json b/tests/fixtures/parity/legacy/verify__invalid_depth_422.json new file mode 100644 index 0000000..5c82768 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__invalid_depth_422.json @@ -0,0 +1,24 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "literal_error", + "loc": [ + "body", + "payload", + "depth" + ], + "msg": "Input should be 'standard' or 'low'", + "ctx": { + "expected": "'standard' or 'low'" + } + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/verify__invalid_language_422.json b/tests/fixtures/parity/legacy/verify__invalid_language_422.json new file mode 100644 index 0000000..8127478 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__invalid_language_422.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unsupported language 'xx-not-a-language'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact." + } +} diff --git a/tests/fixtures/parity/legacy/verify__list_200.json b/tests/fixtures/parity/legacy/verify__list_200.json new file mode 100644 index 0000000..c51ecc1 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__list_200.json @@ -0,0 +1,45 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "language": "en" + }, + { + "verification_id": "7c83247c", + "claim": "The Earth is round.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:28:00.123456+00:00", + "modified_at": null, + "language": "en" + } + ], + "total": 2, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/verify__list_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/verify__list_200_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..bcbe8b3 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__list_200_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "language": "en" + } + ], + "total": 1, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/verify__list_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/verify__list_200_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..9f2e07e --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__list_200_modified_at_same_day_hours_apart.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "modified_at": null, + "language": "en" + } + ], + "total": 1, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/verify__list_clamped_200.json b/tests/fixtures/parity/legacy/verify__list_clamped_200.json new file mode 100644 index 0000000..3d639d4 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__list_clamped_200.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [], + "total": 0, + "page": 1, + "page_size": 100 + } +} diff --git a/tests/fixtures/parity/legacy/verify__list_empty_200.json b/tests/fixtures/parity/legacy/verify__list_empty_200.json new file mode 100644 index 0000000..b419316 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__list_empty_200.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [], + "total": 0, + "page": 1, + "page_size": 20 + } +} diff --git a/tests/fixtures/parity/legacy/verify__list_page2_200.json b/tests/fixtures/parity/legacy/verify__list_page2_200.json new file mode 100644 index 0000000..38ebd2f --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__list_page2_200.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "items": [ + { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "domain": "Science", + "entities": [], + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "language": "en" + } + ], + "total": 3, + "page": 2, + "page_size": 2 + } +} diff --git a/tests/fixtures/parity/legacy/verify__misnamed_field_422.json b/tests/fixtures/parity/legacy/verify__misnamed_field_422.json new file mode 100644 index 0000000..98527f4 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__misnamed_field_422.json @@ -0,0 +1,26 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "missing", + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required" + } + ], + "hint": "Required field 'claim' is missing. Unrecognised fields: statement.", + "doc_url": "https://lenz.io/docs/errors#validation", + "unrecognized_fields": [ + "statement" + ] + } +} diff --git a/tests/fixtures/parity/legacy/verify__missing_claim_422.json b/tests/fixtures/parity/legacy/verify__missing_claim_422.json new file mode 100644 index 0000000..f862968 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__missing_claim_422.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": [ + { + "type": "missing", + "loc": [ + "body", + "payload", + "text" + ], + "msg": "Field required" + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/verify__no_credits_402.json b/tests/fixtures/parity/legacy/verify__no_credits_402.json new file mode 100644 index 0000000..32f50ac --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__no_credits_402.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "No remaining claim checks.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T09:14:00+00:00", + "credits_remaining": 0, + "cost": 10 + } +} diff --git a/tests/fixtures/parity/legacy/verify__replay_later_202.json b/tests/fixtures/parity/legacy/verify__replay_later_202.json new file mode 100644 index 0000000..b6dbf5e --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__replay_later_202.json @@ -0,0 +1,13 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "78ac4e9f234ea3bd" + } +} diff --git a/tests/fixtures/parity/legacy/verify__select_202.json b/tests/fixtures/parity/legacy/verify__select_202.json new file mode 100644 index 0000000..7229ce4 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__select_202.json @@ -0,0 +1,21 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "claim_text": "The Earth is round." + }, + { + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "claim_text": "Water boils at 100C at sea level." + } + ] + } +} diff --git a/tests/fixtures/parity/legacy/verify__select_empty_422.json b/tests/fixtures/parity/legacy/verify__select_empty_422.json new file mode 100644 index 0000000..e2c29b2 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__select_empty_422.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "texts is required and must be non-empty." + } +} diff --git a/tests/fixtures/parity/legacy/verify__select_invalid_selection_422.json b/tests/fixtures/parity/legacy/verify__select_invalid_selection_422.json new file mode 100644 index 0000000..637ab1f --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__select_invalid_selection_422.json @@ -0,0 +1,13 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Selected text was not one of the offered claims: 'The Moon is made of cheese.'", + "code": "invalid_selection", + "error": "invalid_selection" + } +} diff --git a/tests/fixtures/parity/legacy/verify__select_no_selection_pending_409.json b/tests/fixtures/parity/legacy/verify__select_no_selection_pending_409.json new file mode 100644 index 0000000..3b60350 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__select_no_selection_pending_409.json @@ -0,0 +1,13 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This task has no pending claim selection.", + "code": "no_selection_pending", + "error": "no_selection_pending" + } +} diff --git a/tests/fixtures/parity/legacy/verify__select_too_many_422.json b/tests/fixtures/parity/legacy/verify__select_too_many_422.json new file mode 100644 index 0000000..297aef4 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__select_too_many_422.json @@ -0,0 +1,11 @@ +{ + "status": 422, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Cannot select more than 20 claims." + } +} diff --git a/tests/fixtures/parity/legacy/verify__select_unknown_task_404.json b/tests/fixtures/parity/legacy/verify__select_unknown_task_404.json new file mode 100644 index 0000000..09c1e79 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__select_unknown_task_404.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Task not found." + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_cancelled_after_a_while.json b/tests/fixtures/parity/legacy/verify__status_cancelled_after_a_while.json new file mode 100644 index 0000000..0350ab8 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_cancelled_after_a_while.json @@ -0,0 +1,17 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "error": "Cancelled.", + "failure_reason": "cancelled", + "failure_class": "cancelled", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#cancelled" + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_completed.json b/tests/fixtures/parity/legacy/verify__status_completed.json new file mode 100644 index 0000000..8e62516 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_completed.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_completed_after_a_while.json b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while.json new file mode 100644 index 0000000..8e62516 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..3f7a898 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..5a6b9fc --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/verify__status_completed_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..3f7a898 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_completed_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/verify__status_completed_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..5a6b9fc --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_completed_modified_at_same_day_hours_apart.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_failed.json b/tests/fixtures/parity/legacy/verify__status_failed.json new file mode 100644 index 0000000..29f43b1 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_failed.json @@ -0,0 +1,17 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "error": "Pipeline stopped at: research_empty", + "failure_reason": "research_empty", + "failure_class": "insufficient_evidence", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_failed_after_a_while.json b/tests/fixtures/parity/legacy/verify__status_failed_after_a_while.json new file mode 100644 index 0000000..f3a344f --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_failed_after_a_while.json @@ -0,0 +1,17 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "error": "Pipeline stopped: conclusion_failed.", + "failure_reason": "conclusion_failed", + "failure_class": "internal", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#internal" + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_failed_after_a_while_framing.json b/tests/fixtures/parity/legacy/verify__status_failed_after_a_while_framing.json new file mode 100644 index 0000000..2f2bf0c --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_failed_after_a_while_framing.json @@ -0,0 +1,17 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "error": "Pipeline stopped: framing_failed.", + "failure_reason": "framing_failed", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_failed_retryable.json b/tests/fixtures/parity/legacy/verify__status_failed_retryable.json new file mode 100644 index 0000000..3451f74 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_failed_retryable.json @@ -0,0 +1,17 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "error": "Pipeline stopped at: adjudication_failed", + "failure_reason": "adjudication_failed", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_needs_input.json b/tests/fixtures/parity/legacy/verify__status_needs_input.json new file mode 100644 index 0000000..463b486 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_needs_input.json @@ -0,0 +1,24 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "needs_input", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "reason": "multi_claim", + "claims": [ + { + "text": "The Earth is round.", + "domain": "Science" + }, + { + "text": "Water boils at 100C at sea level.", + "domain": "Science" + } + ], + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select." + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_not_a_claim.json b/tests/fixtures/parity/legacy/verify__status_not_a_claim.json new file mode 100644 index 0000000..f787d67 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_not_a_claim.json @@ -0,0 +1,18 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "error": "Not a verifiable claim.", + "failure_reason": "not_a_claim", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "hint": "The input is a greeting, not a statement that can be checked. Send one factual claim, or run the text through /extract to enumerate its claims." + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_not_a_claim_after_a_while.json b/tests/fixtures/parity/legacy/verify__status_not_a_claim_after_a_while.json new file mode 100644 index 0000000..ebe10ba --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_not_a_claim_after_a_while.json @@ -0,0 +1,17 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "error": "Pipeline stopped: not_a_claim.", + "failure_reason": "not_a_claim", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_not_yours_404.json b/tests/fixtures/parity/legacy/verify__status_not_yours_404.json new file mode 100644 index 0000000..09c1e79 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_not_yours_404.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Task not found." + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_older_run_completed.json b/tests/fixtures/parity/legacy/verify__status_older_run_completed.json new file mode 100644 index 0000000..8e62516 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_older_run_completed.json @@ -0,0 +1,99 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "4d44dfaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:21:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_older_run_failed_crashed.json b/tests/fixtures/parity/legacy/verify__status_older_run_failed_crashed.json new file mode 100644 index 0000000..0a8ff9f --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_older_run_failed_crashed.json @@ -0,0 +1,17 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "error": "Pipeline failed.", + "failure_reason": "task_error", + "failure_class": "internal", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#internal" + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_older_run_failed_insufficient_evidence.json b/tests/fixtures/parity/legacy/verify__status_older_run_failed_insufficient_evidence.json new file mode 100644 index 0000000..29f43b1 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_older_run_failed_insufficient_evidence.json @@ -0,0 +1,17 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "error": "Pipeline stopped at: research_empty", + "failure_reason": "research_empty", + "failure_class": "insufficient_evidence", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_older_run_in_progress.json b/tests/fixtures/parity/legacy/verify__status_older_run_in_progress.json new file mode 100644 index 0000000..8ff9472 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_older_run_in_progress.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "progress": { + "step": "research", + "index": 2, + "total": 5, + "elapsed_seconds": 2, + "poll_after_seconds": 5 + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_processing.json b/tests/fixtures/parity/legacy/verify__status_processing.json new file mode 100644 index 0000000..8ff9472 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_processing.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "progress": { + "step": "research", + "index": 2, + "total": 5, + "elapsed_seconds": 2, + "poll_after_seconds": 5 + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_processing_after_a_while.json b/tests/fixtures/parity/legacy/verify__status_processing_after_a_while.json new file mode 100644 index 0000000..077dee8 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_processing_after_a_while.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "progress": { + "step": "adjudication", + "index": 4, + "total": 5, + "elapsed_seconds": 2, + "poll_after_seconds": 5 + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_task_stuck.json b/tests/fixtures/parity/legacy/verify__status_task_stuck.json new file mode 100644 index 0000000..2504c91 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_task_stuck.json @@ -0,0 +1,17 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "error": "The task was never completed and has been marked failed.", + "failure_reason": "task_stuck", + "failure_class": "upstream_unavailable", + "retryable": true, + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + } +} diff --git a/tests/fixtures/parity/legacy/verify__status_unknown_404.json b/tests/fixtures/parity/legacy/verify__status_unknown_404.json new file mode 100644 index 0000000..09c1e79 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__status_unknown_404.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Task not found." + } +} diff --git a/tests/fixtures/parity/legacy/verify__submit_202.json b/tests/fixtures/parity/legacy/verify__submit_202.json new file mode 100644 index 0000000..b6dbf5e --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__submit_202.json @@ -0,0 +1,13 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "78ac4e9f234ea3bd" + } +} diff --git a/tests/fixtures/parity/legacy/verify__submit_202_options.json b/tests/fixtures/parity/legacy/verify__submit_202_options.json new file mode 100644 index 0000000..b6dbf5e --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__submit_202_options.json @@ -0,0 +1,13 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "78ac4e9f234ea3bd" + } +} diff --git a/tests/fixtures/parity/legacy/verify__submit_202_text_alias.json b/tests/fixtures/parity/legacy/verify__submit_202_text_alias.json new file mode 100644 index 0000000..b6dbf5e --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__submit_202_text_alias.json @@ -0,0 +1,13 @@ +{ + "status": 202, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "78ac4e9f234ea3bd" + } +} diff --git a/tests/fixtures/parity/legacy/verify__unauthenticated_401.json b/tests/fixtures/parity/legacy/verify__unauthenticated_401.json new file mode 100644 index 0000000..8dd2fb4 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__unauthenticated_401.json @@ -0,0 +1,11 @@ +{ + "status": 401, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Unauthorized" + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_200.json b/tests/fixtures/parity/legacy/verify__verification_200.json new file mode 100644 index 0000000..b4a8eae --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_200.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_200_covered.json b/tests/fixtures/parity/legacy/verify__verification_200_covered.json new file mode 100644 index 0000000..5ff9574 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_200_covered.json @@ -0,0 +1,93 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "covered", + "reasons": [], + "certificate_id": "def7232d27eda03cf261569aee9948c5", + "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "as_of": "2026-03-10T12:01:30+00:00", + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..c57efcb --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_null.json b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_null.json new file mode 100644 index 0000000..b4a8eae --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_null.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..4480b71 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_same_day_hours_apart.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_set.json b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_set.json new file mode 100644 index 0000000..c57efcb --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_set.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_200_result_json_conclusion_only.json b/tests/fixtures/parity/legacy/verify__verification_200_result_json_conclusion_only.json new file mode 100644 index 0000000..86594fb --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_200_result_json_conclusion_only.json @@ -0,0 +1,56 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [], + "presumed_intent": "", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "sources": [], + "audit": { + "adjudication_summary": "", + "assessments": [], + "debate_pro": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "debate_con": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "panel_agreement": "split" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_200_result_json_empty.json b/tests/fixtures/parity/legacy/verify__verification_200_result_json_empty.json new file mode 100644 index 0000000..86594fb --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_200_result_json_empty.json @@ -0,0 +1,56 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [], + "presumed_intent": "", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "sources": [], + "audit": { + "adjudication_summary": "", + "assessments": [], + "debate_pro": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "debate_con": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "panel_agreement": "split" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_200_result_json_old_shape_strings.json b/tests/fixtures/parity/legacy/verify__verification_200_result_json_old_shape_strings.json new file mode 100644 index 0000000..34ae356 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_200_result_json_old_shape_strings.json @@ -0,0 +1,72 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [], + "presumed_intent": "", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "", + "title": "", + "url": "https://old.example/a", + "snippet": "Old row.", + "date": "" + } + ], + "audit": { + "adjudication_summary": "", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "", + "score": null, + "reasoning": "", + "warnings": [] + } + ], + "debate_pro": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "debate_con": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "panel_agreement": "split" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_404.json b/tests/fixtures/parity/legacy/verify__verification_404.json new file mode 100644 index 0000000..3bf3204 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_404.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Not found." + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_by_task_id_200.json b/tests/fixtures/parity/legacy/verify__verification_by_task_id_200.json new file mode 100644 index 0000000..b4a8eae --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_by_task_id_200.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_failed_409.json b/tests/fixtures/parity/legacy/verify__verification_failed_409.json new file mode 100644 index 0000000..fc6de0a --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_failed_409.json @@ -0,0 +1,19 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This check failed and has no result.", + "code": "verification_failed", + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "hint": "Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "failure_reason": "research_empty", + "failure_class": "insufficient_evidence", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_failed_409_not_a_claim_after_a_while.json b/tests/fixtures/parity/legacy/verify__verification_failed_409_not_a_claim_after_a_while.json new file mode 100644 index 0000000..d0c0aa6 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_failed_409_not_a_claim_after_a_while.json @@ -0,0 +1,19 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This check failed and has no result.", + "code": "verification_failed", + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "hint": "Resubmit to POST /verify if retryable is true. GET /verify/status/7cff18da2d979d6370e54a160be121ad has the full failure.", + "failure_reason": "not_a_claim", + "failure_class": "invalid_input", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#invalid-input" + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_not_ready_409.json b/tests/fixtures/parity/legacy/verify__verification_not_ready_409.json new file mode 100644 index 0000000..d5ace3f --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_not_ready_409.json @@ -0,0 +1,15 @@ +{ + "status": 409, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This check is still running.", + "code": "verification_not_ready", + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "hint": "Poll GET /verify/status/7cff18da2d979d6370e54a160be121ad until it completes, then read its result." + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_not_yours_404.json b/tests/fixtures/parity/legacy/verify__verification_not_yours_404.json new file mode 100644 index 0000000..3bf3204 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_not_yours_404.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Not found." + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_public_anonymous.json b/tests/fixtures/parity/legacy/verify__verification_public_anonymous.json new file mode 100644 index 0000000..6f459a1 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_public_anonymous.json @@ -0,0 +1,83 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "public", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": null + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_public_of_another_user.json b/tests/fixtures/parity/legacy/verify__verification_public_of_another_user.json new file mode 100644 index 0000000..b81a9a7 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_public_of_another_user.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "public", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical in shape.", + "executive_summary": "The claim is verified.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_unknown_task_404.json b/tests/fixtures/parity/legacy/verify__verification_unknown_task_404.json new file mode 100644 index 0000000..cfc00c7 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_unknown_task_404.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "Not found.", + "hint": "Unknown id. If this is a task_id, poll GET /verify/status/dddddddddddddddddddddddddddddddd for its status." + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_zero_retention_expired_410.json b/tests/fixtures/parity/legacy/verify__verification_zero_retention_expired_410.json new file mode 100644 index 0000000..010b258 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_zero_retention_expired_410.json @@ -0,0 +1,13 @@ +{ + "status": 410, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "detail": "This verification is no longer available: its account removes verifications after a set period.", + "code": "purged", + "purged_at": "2026-10-01T09:07:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/verify__verification_zero_retention_served.json b/tests/fixtures/parity/legacy/verify__verification_zero_retention_served.json new file mode 100644 index 0000000..21c8d25 --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__verification_zero_retention_served.json @@ -0,0 +1,95 @@ +{ + "status": 200, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + }, + "body": { + "verification_id": "68ca4aaf", + "claim": "The Earth is round.", + "visibility": "private", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "presumed_intent": "Verify a basic scientific fact", + "verdict": "True", + "confidence": "high", + "lenz_score": 9, + "key_finding": "The Earth is approximately spherical.", + "executive_summary": "The claim is well supported by evidence.", + "warnings": [ + "Relies on limited sources" + ], + "suggested_rewrite": null, + "created_at": "2026-10-01T09:14:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape", + "snippet": "Satellite imagery shows an oblate spheroid.", + "date": "2025-01-15" + }, + { + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth", + "snippet": "Orbital measurements confirm the curvature.", + "date": "2025-01-16" + } + ], + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Claim Precision & Quantitative Accuracy", + "score": 9.0, + "reasoning": "Precision analysis reasoning.", + "warnings": [] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Sources", + "score": 9.0, + "reasoning": "Source audit reasoning.", + "warnings": [ + "weak source A" + ] + } + ], + "debate_pro": { + "role": "Advocate", + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold." + }, + "debate_con": { + "role": "Skeptic", + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + } +} diff --git a/tests/fixtures/parity/legacy/webhook__certificate_timestamped.json b/tests/fixtures/parity/legacy/webhook__certificate_timestamped.json new file mode 100644 index 0000000..a47b14c --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__certificate_timestamped.json @@ -0,0 +1,27 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "certificate.timestamped", + "verification_id": "68ca4aaf", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "batch_id": null, + "status": "completed", + "result": null, + "needs_input": null, + "coverage": { + "status": "covered", + "reasons": [], + "certificate_id": "def7232d27eda03cf261569aee9948c5", + "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "as_of": "2026-09-03T10:00:00+00:00", + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + }, + "error": null, + "attempt": 1, + "delivered_at": "2026-10-01T09:28:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__certificate_timestamped_review_child.json b/tests/fixtures/parity/legacy/webhook__certificate_timestamped_review_child.json new file mode 100644 index 0000000..028efa3 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__certificate_timestamped_review_child.json @@ -0,0 +1,28 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "certificate.timestamped", + "verification_id": "68ca4aaf", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "batch_id": null, + "status": "completed", + "result": null, + "needs_input": null, + "coverage": { + "status": "covered", + "reasons": [], + "certificate_id": "def7232d27eda03cf261569aee9948c5", + "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "as_of": "2026-09-03T10:00:00+00:00", + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + }, + "error": null, + "review_id": "d6b2bd72", + "attempt": 1, + "delivered_at": "2026-10-01T09:28:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__citecheck_completed.json b/tests/fixtures/parity/legacy/webhook__citecheck_completed.json new file mode 100644 index 0000000..447a098 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__citecheck_completed.json @@ -0,0 +1,134 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "citecheck.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "citecheck_id": "98c0e7d5", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "status": "completed", + "citecheck": { + "citecheck_id": "98c0e7d5", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T09:35:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 2 + }, + "summary": { + "citations_found": 2, + "citations_selected": 2, + "citation_limit": 2, + "citation_limit_reached": false, + "citation_checks": { + "checked": 2, + "unchecked": 0, + "failed": 0 + }, + "citation_issues": 1 + }, + "credits": { + "charged": 2 + }, + "citations": [ + { + "index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "result": { + "finding": "contradicted", + "source": "support", + "is_issue": true + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "support": "contradicted", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + }, + { + "index": 1, + "reference": "https://example.org/statement", + "cited_url": "https://example.org/statement", + "doi": null, + "statement": "The agency said so in a statement.", + "quotes": [], + "position": null, + "result": { + "finding": "supported", + "source": "support", + "is_issue": false + }, + "check": { + "status": "completed", + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "page_published_date": null, + "page_language": "en", + "source_url": "https://example.org/statement", + "source_version": null, + "support": "supported", + "snippet": "The source says so.", + "rationale": "The page states it.", + "quote": null, + "doi_registered": null, + "metadata": null, + "metadata_differences": [], + "registered": null, + "unchecked_reason": null, + "hint": null, + "failure": null, + "missing_quote": null + } + } + ], + "citation_issues": [ + { + "citation_index": 0, + "reference": "https://example.gov/report-2024", + "cited_url": "https://example.gov/report-2024", + "doi": null, + "statement": "Unemployment fell to 4.1% in 2024.", + "quotes": [], + "position": null, + "finding": "contradicted", + "source": "support", + "snippet": "The source says so.", + "rationale": "The page states it.", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "failure": null + } + ], + "citation_failures": [], + "failure": null, + "more_citations": [] + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:42:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__citecheck_failed.json b/tests/fixtures/parity/legacy/webhook__citecheck_failed.json new file mode 100644 index 0000000..19627f2 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__citecheck_failed.json @@ -0,0 +1,47 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "citecheck.failed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "citecheck_id": "98c0e7d5", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "status": "failed", + "citecheck": { + "citecheck_id": "98c0e7d5", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T09:35:00.123456Z", + "language": "en", + "poll_after_seconds": null, + "policy": { + "max_citations": 20 + }, + "summary": { + "citations_found": null, + "citations_selected": null, + "citation_limit": 20, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0 + }, + "credits": { + "charged": 0 + }, + "citations": [], + "citation_issues": [], + "citation_failures": [], + "failure": { + "failure_reason": "no_citations", + "failure_class": "invalid_input", + "retryable": false, + "hint": "The text has no citation to check: no link, DOI or numbered reference with one.", + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_citations": null + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:42:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__review_completed.json b/tests/fixtures/parity/legacy/webhook__review_completed.json new file mode 100644 index 0000000..1149eea --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__review_completed.json @@ -0,0 +1,156 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "review.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review_id": "8cb2f001", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "status": "completed", + "review": { + "review_id": "8cb2f001", + "view": "full", + "status": "completed", + "outcome": "issues_found", + "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T09:35:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 1, + "completed": 1, + "failed": 0 + }, + "issues": 1, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 11 + }, + "poll_after_seconds": null, + "issues": [ + { + "claim_index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "verified_claim": null, + "verdict": "False", + "confidence": "high", + "source": "verification", + "verification_id": "8ceed6f0", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", + "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "failure": null, + "suggested_edits": null + } + ], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "False", + "confidence": "high", + "source": "verification", + "is_issue": true + }, + "assessment": { + "status": "completed", + "verdict": "False", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [ + "verdict" + ], + "disposition": "planned" + }, + "verification": { + "status": "completed", + "content_status": "available", + "task_id": "5ccac77f53ff49328ec134fb29d66542", + "verification_id": "8ceed6f0", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "verdict": "False", + "confidence": "high", + "lenz_score": 2, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "warnings": [ + "w1" + ], + "created_at": "2026-10-01T09:56:00.123456+00:00", + "modified_at": null, + "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", + "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "failure": null + }, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + }, + "attempt": 1, + "delivered_at": "2026-10-01T10:03:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__review_completed_key_default_url.json b/tests/fixtures/parity/legacy/webhook__review_completed_key_default_url.json new file mode 100644 index 0000000..35c4a30 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__review_completed_key_default_url.json @@ -0,0 +1,105 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "review.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review_id": "8cb2f001", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "status": "completed", + "review": { + "review_id": "8cb2f001", + "view": "full", + "status": "completed", + "outcome": "clean", + "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T09:35:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": 1, + "claim_limit": 20, + "claim_limit_reached": false, + "input_truncated": false, + "assessments": { + "completed": 1, + "failed": 0 + }, + "verifications": { + "planned": 0, + "completed": 0, + "failed": 0 + }, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 1 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [ + { + "index": 0, + "claim": "The Eiffel Tower is in Berlin.", + "positions": null, + "result": { + "verdict": "True", + "confidence": "high", + "source": "assessment", + "is_issue": false + }, + "assessment": { + "status": "completed", + "verdict": "True", + "confidence": "high", + "rationale": null, + "dissent": null, + "verification_url": null, + "error_code": null, + "identified_claims": [], + "hint": null, + "suggested_rewrite": null, + "failure": null + }, + "escalation": { + "matched_rules": [], + "disposition": "not_selected" + }, + "verification": null, + "suggested_edits": null + } + ], + "citations": [], + "failure": null, + "more_claims": [], + "more_claim_locations": [], + "more_citations": [] + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:42:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__review_completed_oversized_rebuilt.json b/tests/fixtures/parity/legacy/webhook__review_completed_oversized_rebuilt.json new file mode 100644 index 0000000..6248eaf --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__review_completed_oversized_rebuilt.json @@ -0,0 +1,11 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "review.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review_id": "8cb2f001", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "status": "completed" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__review_failed.json b/tests/fixtures/parity/legacy/webhook__review_failed.json new file mode 100644 index 0000000..294d967 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__review_failed.json @@ -0,0 +1,73 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "review.failed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "review_id": "8cb2f001", + "task_id": "13610f0b64b63e006dc66364e0e82c85", + "status": "failed", + "review": { + "review_id": "8cb2f001", + "view": "full", + "status": "failed", + "outcome": "unchecked", + "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T09:35:00.123456Z", + "language": "en", + "policy": { + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ], + "confidence": [ + "low" + ], + "max_assessments": 20, + "max_verifications": 5, + "depth": "standard", + "max_citations": 0, + "suggest_edits": false + }, + "summary": { + "claims_selected": null, + "claim_limit": 20, + "claim_limit_reached": null, + "input_truncated": false, + "assessments": null, + "verifications": null, + "issues": 0, + "citations_found": null, + "citations_selected": null, + "citation_limit": null, + "citation_limit_reached": null, + "citation_checks": null, + "citation_issues": 0, + "citations_skipped": null + }, + "credits": { + "charged": 0 + }, + "poll_after_seconds": null, + "issues": [], + "failures": [], + "citation_issues": [], + "citation_failures": [], + "claims": [], + "citations": [], + "failure": { + "failure_reason": "no_claim", + "failure_class": "invalid_input", + "retryable": false, + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", + "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "more_claims": null, + "more_claim_locations": null, + "more_citations": null + }, + "attempt": 1, + "delivered_at": "2026-10-01T09:42:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_completed.json b/tests/fixtures/parity/legacy/webhook__verification_completed.json new file mode 100644 index 0000000..68b9dbb --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_completed.json @@ -0,0 +1,107 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.completed", + "verification_id": "68ca4aaf", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "batch_id": null, + "status": "completed", + "result": { + "verification_id": "68ca4aaf", + "claim": "The Eiffel Tower is in Berlin.", + "visibility": "private", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "presumed_intent": "Check where a landmark is.", + "verdict": "False", + "confidence": "high", + "lenz_score": 1, + "key_finding": "The Eiffel Tower is in Paris.", + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "warnings": [ + "Only two sources were found." + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "created_at": "2026-10-01T09:21:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "date": "2025-01-15" + }, + { + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "date": "" + } + ], + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Evidence", + "score": 1.0, + "reasoning": "Both sources place the tower in Paris.", + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Evidence", + "score": 2.0, + "reasoning": "The encyclopedia entry is unambiguous.", + "warnings": [] + } + ], + "debate_pro": { + "role": "pro", + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable." + }, + "debate_con": { + "role": "con", + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + }, + "needs_input": null, + "coverage": null, + "error": null, + "attempt": 1, + "delivered_at": "2026-10-01T09:28:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_completed_in_batch.json b/tests/fixtures/parity/legacy/webhook__verification_completed_in_batch.json new file mode 100644 index 0000000..be55b0a --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_completed_in_batch.json @@ -0,0 +1,107 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.completed", + "verification_id": "68ca4aaf", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "batch_id": "4ee0c3aa1b671eaa", + "status": "completed", + "result": { + "verification_id": "68ca4aaf", + "claim": "The Eiffel Tower is in Berlin.", + "visibility": "private", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "presumed_intent": "Check where a landmark is.", + "verdict": "False", + "confidence": "high", + "lenz_score": 1, + "key_finding": "The Eiffel Tower is in Paris.", + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "warnings": [ + "Only two sources were found." + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "created_at": "2026-10-01T09:28:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "date": "2025-01-15" + }, + { + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "date": "" + } + ], + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Evidence", + "score": 1.0, + "reasoning": "Both sources place the tower in Paris.", + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Evidence", + "score": 2.0, + "reasoning": "The encyclopedia entry is unambiguous.", + "warnings": [] + } + ], + "debate_pro": { + "role": "pro", + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable." + }, + "debate_con": { + "role": "con", + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + }, + "needs_input": null, + "coverage": null, + "error": null, + "attempt": 1, + "delivered_at": "2026-10-01T09:35:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json new file mode 100644 index 0000000..c9af648 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json @@ -0,0 +1,107 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.completed", + "verification_id": "68ca4aaf", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "batch_id": null, + "status": "completed", + "result": { + "verification_id": "68ca4aaf", + "claim": "The Eiffel Tower is in Berlin.", + "visibility": "private", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "presumed_intent": "Check where a landmark is.", + "verdict": "False", + "confidence": "high", + "lenz_score": 1, + "key_finding": "The Eiffel Tower is in Paris.", + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "warnings": [ + "Only two sources were found." + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "created_at": "2026-10-01T23:55:00.123456+00:00", + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "sources": [ + { + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "date": "2025-01-15" + }, + { + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "date": "" + } + ], + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Evidence", + "score": 1.0, + "reasoning": "Both sources place the tower in Paris.", + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Evidence", + "score": 2.0, + "reasoning": "The encyclopedia entry is unambiguous.", + "warnings": [] + } + ], + "debate_pro": { + "role": "pro", + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable." + }, + "debate_con": { + "role": "con", + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + }, + "needs_input": null, + "coverage": null, + "error": null, + "attempt": 1, + "delivered_at": "2026-10-01T09:35:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_same_day_hours_apart.json new file mode 100644 index 0000000..6d2f10a --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_same_day_hours_apart.json @@ -0,0 +1,107 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.completed", + "verification_id": "68ca4aaf", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "batch_id": null, + "status": "completed", + "result": { + "verification_id": "68ca4aaf", + "claim": "The Eiffel Tower is in Berlin.", + "visibility": "private", + "depth": "standard", + "domain": "Geography", + "entities": [ + { + "name": "Eiffel Tower", + "qid": null + }, + { + "name": "Berlin", + "qid": null + } + ], + "presumed_intent": "Check where a landmark is.", + "verdict": "False", + "confidence": "high", + "lenz_score": 1, + "key_finding": "The Eiffel Tower is in Paris.", + "executive_summary": "The Eiffel Tower stands in Paris, France, not in Berlin.", + "warnings": [ + "Only two sources were found." + ], + "suggested_rewrite": "The Eiffel Tower is in Paris.", + "created_at": "2026-10-01T08:00:00.123456+00:00", + "modified_at": null, + "sources": [ + { + "source_name": "Example Encyclopedia", + "title": "Eiffel Tower", + "url": "https://example.org/eiffel-tower", + "snippet": "The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France.", + "date": "2025-01-15" + }, + { + "source_name": "Example Travel", + "title": "Visiting Paris", + "url": "https://example.com/visit-paris", + "snippet": "Most visitors climb the tower on their first day in Paris.", + "date": "" + } + ], + "audit": { + "adjudication_summary": "Both reviewers found it false.", + "assessments": [ + { + "panelist_name": "Reviewer A", + "focus_area": "Evidence", + "score": 1.0, + "reasoning": "Both sources place the tower in Paris.", + "warnings": [ + "Example Travel is a travel blog." + ] + }, + { + "panelist_name": "Reviewer B", + "focus_area": "Evidence", + "score": 2.0, + "reasoning": "The encyclopedia entry is unambiguous.", + "warnings": [] + } + ], + "debate_pro": { + "role": "pro", + "argument": "Some guides place it in Berlin.", + "rebuttal": "None of them are reliable." + }, + "debate_con": { + "role": "con", + "argument": "Every source places it in Paris.", + "rebuttal": "The pro case cites no source." + }, + "panel_agreement": "unanimous" + }, + "language": "en", + "coverage": { + "status": "uncovered", + "reasons": [ + "plan" + ], + "certificate_id": null, + "certificate_url": null, + "as_of": null, + "currency": "EUR", + "cap": 10000, + "aggregate": 500000, + "terms_version": "v1" + } + }, + "needs_input": null, + "coverage": null, + "error": null, + "attempt": 1, + "delivered_at": "2026-10-01T09:28:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_failed_insufficient_evidence.json b/tests/fixtures/parity/legacy/webhook__verification_failed_insufficient_evidence.json new file mode 100644 index 0000000..e44f526 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_failed_insufficient_evidence.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.failed", + "verification_id": null, + "task_id": "7cff18da2d979d6370e54a160be121ad", + "batch_id": null, + "status": "failed", + "result": null, + "needs_input": null, + "coverage": null, + "error": "research_insufficient", + "failure_class": "insufficient_evidence", + "retryable": false, + "attempt": 1, + "delivered_at": "2026-10-01T09:14:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_failed_not_a_claim.json b/tests/fixtures/parity/legacy/webhook__verification_failed_not_a_claim.json new file mode 100644 index 0000000..d27f1f1 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_failed_not_a_claim.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.failed", + "verification_id": null, + "task_id": "7cff18da2d979d6370e54a160be121ad", + "batch_id": null, + "status": "failed", + "result": null, + "needs_input": null, + "coverage": null, + "error": "not_a_claim", + "failure_class": "invalid_input", + "retryable": false, + "attempt": 1, + "delivered_at": "2026-10-01T09:14:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_failed_upstream_unavailable.json b/tests/fixtures/parity/legacy/webhook__verification_failed_upstream_unavailable.json new file mode 100644 index 0000000..14ba36a --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_failed_upstream_unavailable.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.failed", + "verification_id": null, + "task_id": "7cff18da2d979d6370e54a160be121ad", + "batch_id": null, + "status": "failed", + "result": null, + "needs_input": null, + "coverage": null, + "error": "framing_failed", + "failure_class": "upstream_unavailable", + "retryable": true, + "attempt": 1, + "delivered_at": "2026-10-01T09:14:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_needs_input_multi_claim.json b/tests/fixtures/parity/legacy/webhook__verification_needs_input_multi_claim.json new file mode 100644 index 0000000..4d08431 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_needs_input_multi_claim.json @@ -0,0 +1,30 @@ +{ + "status": 200, + "headers": {}, + "body": { + "event": "verification.needs_input", + "verification_id": null, + "task_id": "7cff18da2d979d6370e54a160be121ad", + "batch_id": null, + "status": "needs_input", + "result": null, + "needs_input": { + "reason": "multi_claim", + "claims": [ + { + "text": "The Earth is round.", + "domain": "" + }, + { + "text": "The Moon is made of cheese.", + "domain": "Science" + } + ], + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select." + }, + "coverage": null, + "error": null, + "attempt": 1, + "delivered_at": "2026-10-01T09:14:00.123456+00:00" + } +} diff --git a/tests/fixtures/parity/requests.json b/tests/fixtures/parity/requests.json new file mode 100644 index 0000000..699837e --- /dev/null +++ b/tests/fixtures/parity/requests.json @@ -0,0 +1,68 @@ +{ + "citecheck_default": { + "text": "The Eiffel Tower is in Berlin. See https://example.org/eiffel." + }, + "citecheck_pairs": { + "language": "fr", + "pairs": [ + { + "statement": "The tower is in Paris.", + "url": "https://example.org/eiffel" + } + ] + }, + "citecheck_webhook_empty": { + "text": "The Eiffel Tower is in Berlin. See https://example.org/eiffel.", + "webhook_url": "" + }, + "citecheck_webhook_url": { + "max_citations": 4, + "text": "The Eiffel Tower is in Berlin. See https://example.org/eiffel.", + "webhook_url": "https://hooks.example.test/x" + }, + "review_default": { + "text": "The Eiffel Tower is in Berlin. See https://example.org/eiffel.", + "visibility": "private" + }, + "review_options": { + "escalate": { + "confidence": [ + "low" + ], + "depth": "low", + "max_assessments": 5, + "max_citations": 3, + "max_verifications": 2, + "suggest_edits": true, + "verdicts": [ + "False" + ] + }, + "language": "de", + "text": "The Eiffel Tower is in Berlin. See https://example.org/eiffel.", + "visibility": "unlisted" + }, + "review_webhook_empty": { + "text": "The Eiffel Tower is in Berlin. See https://example.org/eiffel.", + "visibility": "private", + "webhook_url": "" + }, + "review_webhook_url": { + "text": "The Eiffel Tower is in Berlin. See https://example.org/eiffel.", + "visibility": "private", + "webhook_url": "https://hooks.example.test/x" + }, + "verify_batch_webhook_url": { + "claims": [ + { + "text": "The Earth is round." + } + ], + "webhook_url": "https://hooks.example.test/x" + }, + "verify_webhook_url": { + "source_url": "", + "text": "The Earth is round.", + "webhook_url": "https://hooks.example.test/x" + } +} diff --git a/tests/parity_generate.py b/tests/parity_generate.py new file mode 100644 index 0000000..e104cb9 --- /dev/null +++ b/tests/parity_generate.py @@ -0,0 +1,37 @@ +"""Freeze what the previous release made of every original-shape response. + +Run once against the code BEFORE this SDK read the newer response shape, with +that code first on the path, e.g. from a checkout of the parent commit:: + + PYTHONPATH=/path/to/parent-checkout/src:tests python tests/parity_generate.py + +It writes ``tests/fixtures/parity/expected/.json`` and +``tests/fixtures/parity/requests.json``: the oracle +``tests/test_parity.py`` holds both response shapes to. Do not regenerate it +with the current code; that would make the test compare the code with itself. +""" + +from __future__ import annotations + +import json +import sys + +from parity_observe import FIXTURES, load, names, observe +from parity_requests import bodies + +import lenz_io + + +def main() -> None: + print(f"observing with lenz_io from {lenz_io.__file__}", file=sys.stderr) + out = FIXTURES / "expected" + out.mkdir(exist_ok=True) + for name in names(): + result = observe(name, load("legacy", name)) + (out / name).write_text(json.dumps(result, indent=2, ensure_ascii=False, sort_keys=True) + "\n") + (FIXTURES / "requests.json").write_text(json.dumps(bodies(), indent=2, sort_keys=True) + "\n") + print(f"wrote {len(names())} files and requests.json", file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/tests/parity_observe.py b/tests/parity_observe.py new file mode 100644 index 0000000..242d5e0 --- /dev/null +++ b/tests/parity_observe.py @@ -0,0 +1,233 @@ +"""What the SDK and the CLI make of one response, as plain JSON. + +Shared by ``tests/test_parity.py`` and ``tests/parity_generate.py``. It uses +only the public surface that existed before this SDK read the newer response +shape, so the generator can run it against the previous release's code and +freeze the result (``tests/fixtures/parity/expected/``): the frozen output is +the oracle both response shapes are held to. + +Fixture names are ``__.json``; the area picks what is observed. +""" + +from __future__ import annotations + +import contextlib +import io +import json +import warnings +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +from rich.console import Console + +import lenz_io.cli.render as render_mod +from lenz_io import errors as errors_mod +from lenz_io import models +from lenz_io.cli import citecheck as citecheck_cli +from lenz_io.cli import review as review_cli +from lenz_io.cli.errors import friendly_text, to_payload +from lenz_io.client import Lenz +from lenz_io.webhooks import parse_webhook + +FIXTURES = Path(__file__).parent / "fixtures" / "parity" +MISSING = "" + +#: The time the CLI's relative reset dates are rendered against. +FROZEN_NOW = datetime(2026, 10, 2, 12, 0, 0, tzinfo=timezone.utc) + +#: Every attribute an SDK exception may carry, read when present. +_ERROR_ATTRS = ( + "message", + "cause", + "fix", + "doc_url", + "request_id", + "status_code", + "code", + "retry_after", + "limit", + "reset_in_seconds", + "upgrade_url", + "remaining", + "resets_at", + "requested", + "credit_balance", + "cost", + "errors", + "task_id", + "status", + "hint", + "failure_reason", + "failure_class", + "retryable", + "purged_at", + "kind", + "payload", +) + + +class _FrozenDatetime(datetime): + @classmethod + def now(cls, tz: Any = None) -> Any: # type: ignore[override] + return FROZEN_NOW if tz else FROZEN_NOW.replace(tzinfo=None) + + +def _jsonable(value: Any) -> Any: + if hasattr(value, "model_dump"): + return value.model_dump(mode="json") + return json.loads(json.dumps(value, default=str)) + + +def attr_view(obj: Any, template: Any) -> Any: + """Read ``obj`` by ATTRIBUTE along the keys of ``template`` (a dump). + + A dump shows only what a model serialises; this reads what code reading + the attributes gets, so a newer-shape response can be held to the dump the + original shape produced. + """ + if isinstance(template, dict): + out = {} + for key, sub in template.items(): + if isinstance(obj, dict): + value = obj.get(key, MISSING) + else: + value = getattr(obj, key, MISSING) + out[key] = MISSING if value is MISSING else attr_view(value, sub) + return out + if isinstance(template, list): + items = list(obj) if isinstance(obj, (list, tuple)) else [] + if len(items) != len(template): + return _jsonable(obj) + return [attr_view(o, t) for o, t in zip(items, template, strict=True)] + return _jsonable(obj) + + +def _console() -> tuple[Console, io.StringIO]: + buf = io.StringIO() + return Console(file=buf, no_color=True, width=120, highlight=False, force_terminal=False), buf + + +def _render(fn: Any, *args: Any, json_mode: bool = False, **kwargs: Any) -> str: + out = render_mod.Output(json_mode=json_mode, no_color=True) + out.json_mode = json_mode + out.console, buf = _console() + out.err, _ = _console() + stdout = io.StringIO() + real_dt = render_mod.datetime + render_mod.datetime = _FrozenDatetime # type: ignore[misc] + try: + with contextlib.redirect_stdout(stdout): + fn(out, *args, **kwargs) + except SystemExit as exc: + buf.write(f"") + finally: + render_mod.datetime = real_dt # type: ignore[misc] + return buf.getvalue() + stdout.getvalue() + + +def _error_view(err: BaseException) -> dict[str, Any]: + view: dict[str, Any] = {"type": type(err).__name__} + for name in _ERROR_ATTRS: + if name in vars(err) or hasattr(type(err), name): + view[name] = _jsonable(getattr(err, name)) + view["friendly_text"] = friendly_text(err) + view["payload_json"] = _jsonable(to_payload(err)) + return view + + +def _model_for(name: str) -> Any: + area = name.split("__", 1)[0] + case = name.split("__", 1)[1] + if area == "extract": + return models.ExtractedClaims + if area == "assess": + return models.AssessResponse + if area == "account" and case.startswith("me_usage"): + return models.Usage + if area == "account" and case.startswith("library"): + return models.LibraryList + if area == "review": + return models.ReviewStarted if case.startswith(("receipt", "idempotent", "replay")) else models.ReviewFull + if area == "citecheck": + return models.CitecheckStarted if case.startswith(("receipt", "idempotent")) else models.Citecheck + if area == "verify": + if case.startswith("status_"): + return models.TaskStatus + if case.startswith(("batch_", "select_")): + return models.BatchAccepted + if case.startswith("list"): + return models.VerificationList + if case.startswith("verification_"): + return models.Verification + return models.TaskAccepted + return None + + +def observe(name: str, fixture: dict[str, Any]) -> dict[str, Any]: + """Everything the SDK and the CLI produce from one recorded response.""" + status, body = fixture["status"], fixture["body"] + headers = {k: str(v) for k, v in (fixture.get("headers") or {}).items()} + result: dict[str, Any] = {} + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + if name.startswith("webhook__"): + event = parse_webhook(body) + view: dict[str, Any] = {"type": type(event).__name__} + for key, value in vars(event).items(): + if key != "raw": + view[key] = _jsonable(value) + result["event"] = view + return result + if status >= 400: + err = errors_mod.map_response_to_error(status, json.dumps(body).encode(), headers) + result["error"] = _error_view(err) + return result + cls = _model_for(name) + if cls is None: + return result + model = cls.model_validate(body) + result["dump"] = model.model_dump(mode="json") + result["render_json"] = None + if cls is models.ExtractedClaims: + result["render"] = _render(render_mod.render_extract, model) + result["render_json"] = _render(render_mod.render_extract, model, json_mode=True) + elif cls is models.AssessResponse: + result["render"] = _render(render_mod.render_assess, model) + result["render_json"] = _render(render_mod.render_assess, model, json_mode=True) + elif cls is models.Usage: + result["render"] = _render(render_mod.render_usage, model) + result["render_json"] = _render(render_mod.render_usage, model, json_mode=True) + elif cls is models.Verification: + result["render"] = _render(render_mod.render_verification_full, model) + result["render_concise"] = _render(render_mod.render_verification, model) + result["render_json"] = _render(render_mod.render_verification_full, model, json_mode=True) + elif cls is models.TaskStatus: + result["render"] = _render(render_mod.render_task_status, model, task_id="t") + result["render_json"] = _render(render_mod.render_task_status, model, task_id="t", json_mode=True) + client = Lenz(api_key="lenz_" + "0" * 32) + try: + verification = client._verification_from_terminal(model, "t") + result["wait"] = {"returned": verification.model_dump(mode="json")} + except errors_mod.LenzError as exc: + result["wait"] = _error_view(exc) + finally: + client.close() + if model.status == "completed" and model.result is not None: + result["render_verification"] = _render(render_mod.render_verification_full, model.result) + elif cls is models.ReviewFull: + result["render"] = _render(review_cli.render_review, model) + result["render_issues"] = _render(review_cli.render_review, model, issues_only=True) + result["exit_code"] = review_cli.exit_code_for_review(model) + elif cls is models.Citecheck: + result["render"] = _render(citecheck_cli.render_citecheck, model) + result["exit_code"] = citecheck_cli.exit_code_for_citecheck(model) + return result + + +def load(shape: str, name: str) -> dict[str, Any]: + return json.loads((FIXTURES / shape / name).read_text()) + + +def names() -> list[str]: + return sorted(p.name for p in (FIXTURES / "legacy").glob("*.json")) diff --git a/tests/parity_requests.py b/tests/parity_requests.py new file mode 100644 index 0000000..826cc9f --- /dev/null +++ b/tests/parity_requests.py @@ -0,0 +1,99 @@ +"""The request bodies the SDK sends, for ``tests/test_parity.py``. + +Like ``parity_observe``, this uses only what the previous release had, so +``parity_generate.py`` can freeze the previous release's bodies as the +oracle (``tests/fixtures/parity/requests.json``). +""" + +from __future__ import annotations + +import json +from typing import Any + +import respx + +from lenz_io.client import DEFAULT_BASE_URL, Lenz + +DRAFT = "The Eiffel Tower is in Berlin. See https://example.org/eiffel." + +#: (name, method, path, response, kwargs). The /review and /citecheck rows pin +#: ``webhook_url`` in all three states: unset, ``""`` (no webhook) and a URL. +CALLS: list[tuple[str, str, str, dict[str, Any], dict[str, Any]]] = [ + ("review_default", "review", "/review", {"review_id": "r1", "status": "queued"}, {"text": DRAFT}), + ("review_webhook_empty", "review", "/review", {"review_id": "r1"}, {"text": DRAFT, "webhook_url": ""}), + ( + "review_webhook_url", + "review", + "/review", + {"review_id": "r1"}, + {"text": DRAFT, "webhook_url": "https://hooks.example.test/x"}, + ), + ( + "review_options", + "review", + "/review", + {"review_id": "r1"}, + { + "text": DRAFT, + "verdicts": ["False"], + "confidence": ["low"], + "max_assessments": 5, + "max_verifications": 2, + "depth": "low", + "max_citations": 3, + "suggest_edits": True, + "language": "de", + "visibility": "unlisted", + }, + ), + ("citecheck_default", "citecheck", "/citecheck", {"citecheck_id": "c1"}, {"text": DRAFT}), + ("citecheck_webhook_empty", "citecheck", "/citecheck", {"citecheck_id": "c1"}, {"text": DRAFT, "webhook_url": ""}), + ( + "citecheck_webhook_url", + "citecheck", + "/citecheck", + {"citecheck_id": "c1"}, + {"text": DRAFT, "webhook_url": "https://hooks.example.test/x", "max_citations": 4}, + ), + ( + "citecheck_pairs", + "citecheck", + "/citecheck", + {"citecheck_id": "c1"}, + {"pairs": [{"statement": "The tower is in Paris.", "url": "https://example.org/eiffel"}], "language": "fr"}, + ), + ( + "verify_webhook_url", + "verify_and_submit", + "/verify", + {"task_id": "t1", "status": "queued"}, + {"claim": "The Earth is round.", "webhook_url": "https://hooks.example.test/x"}, + ), + ( + "verify_batch_webhook_url", + "verify_batch", + "/verify/batch", + {"batch_id": "b1", "items": []}, + {"claims": [{"claim": "The Earth is round."}], "webhook_url": "https://hooks.example.test/x"}, + ), +] + + +def capture(method: str, path: str, response: dict[str, Any], kwargs: dict[str, Any]) -> Any: + client = Lenz(api_key="lenz_" + "0" * 32) + try: + with respx.mock(base_url=DEFAULT_BASE_URL) as mock: + route = mock.post(path).respond(202, json=response) + if method == "verify_and_submit": + client._verify_submit(claim=kwargs["claim"], webhook_url=kwargs["webhook_url"], idempotency_key="k") + elif method == "verify_batch": + client.verify_batch(idempotency_key="k", **kwargs) + else: + getattr(client, method)(idempotency_key="k", **kwargs) + return json.loads(route.calls.last.request.content) + finally: + client.close() + + +def bodies() -> dict[str, Any]: + return {name: capture(method, path, response, kwargs) for name, method, path, response, kwargs in CALLS} diff --git a/tests/test_cli.py b/tests/test_cli.py index caa271a..1051d39 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -940,7 +940,7 @@ def test_usage_json_success(monkeypatch): assert payload["verify"]["bonus"] == 20 assert payload["assess"]["remaining"] == 5070 assert payload["extract"]["calls_today"] == 4 - # The deprecated alias is still emitted (server sends it until 2026-11-29) + # The deprecated alias is still emitted (the server keeps sending it to existing callers) # and dumping it must not warn — see tests/test_usage_models.py. assert payload["verify"]["credits"] == 20 diff --git a/tests/test_input_aliases.py b/tests/test_input_aliases.py index f1013f5..ca59dbc 100644 --- a/tests/test_input_aliases.py +++ b/tests/test_input_aliases.py @@ -52,7 +52,8 @@ def test_positional_claim_is_unchanged(self, client): with respx.mock(base_url=DEFAULT_BASE) as r: route = r.post("/verify").respond(202, json={"task_id": "tsk_1", "status": "queued"}) client.verify(CLAIM) - assert _body(route) == {"text": CLAIM, "source_url": "", "webhook_url": ""} + # No ``webhook_url`` unless one was given: omitted means the key's default. + assert _body(route) == {"text": CLAIM, "source_url": ""} class TestVerifyBatch: diff --git a/tests/test_parity.py b/tests/test_parity.py new file mode 100644 index 0000000..c5fea40 --- /dev/null +++ b/tests/test_parity.py @@ -0,0 +1,207 @@ +"""Both response shapes give existing code exactly what the previous release did. + +The oracle in ``tests/fixtures/parity/expected/`` was produced by the code +BEFORE this SDK read the newer response shape (see +``tests/parity_generate.py``), from the original-shape responses in +``tests/fixtures/parity/legacy/``. Each response has its newer-shape twin in +``tests/fixtures/parity/canonical/`` (the same answer, as the API's newer +version sends it). + +* An original-shape response must produce the frozen output byte for byte: + the model dump, every CLI rendering (text and ``--json``), the exception + ``wait`` raises, the error an HTTP error maps to, the parsed webhook. +* Its newer-shape twin must produce the same values through every attribute + the previous release had, the same CLI text, the same ``wait`` outcome and + the same error, except for the few values the newer shape does not carry, + listed one by one in ``KNOWN_GAPS`` with the reason. + +``model_dump()`` and the CLI's ``--json`` show the shape the server sent, so +they are compared for the original shape only. +""" + +from __future__ import annotations + +import json +import warnings +from typing import Any + +import pytest +from parity_observe import FIXTURES, MISSING, _model_for, attr_view, load, names, observe + +EXPECTED = FIXTURES / "expected" + +# ── What the newer shape cannot reproduce ─────────────────────────────── +# +# Each gap is allowed only where the two recorded responses themselves differ +# in the value it comes from: a rule never excuses a difference the SDK made. + +#: An exception's text fields: built from the body's ``detail``. +_MESSAGE_PATHS = ("message", "cause", "friendly_text", "payload_json.error.message") + + +def _failure(body: dict[str, Any]) -> dict[str, Any]: + failure = body.get("failure") + return failure if isinstance(failure, dict) else {} + + +def _validation_items(body: dict[str, Any]) -> Any: + detail = body.get("detail") + return detail if isinstance(detail, list) else body.get("errors", []) + + +def _allowed(name: str, path: str, legacy: dict[str, Any], canonical: dict[str, Any]) -> str | None: + """Why ``path`` may differ for ``name``, or ``None`` when it may not.""" + lb, cb = legacy["body"], canonical["body"] + head, _, rest = path.partition(".") + if head == "error": + if rest in _MESSAGE_PATHS and lb.get("detail") != cb.get("detail"): + return "the server words `detail` differently (a 422 sends a sentence, not the list)" + if rest == "code" and lb.get("code") != cb.get("code"): + return "the server sends a different (or a first) `code`" + if rest.startswith("errors") and _validation_items(lb) != _validation_items(cb): + return "the server's field errors differ" + if rest in ("hint", "fix", "friendly_text", "payload_json.error.fix") and lb.get("hint") != cb.get("hint"): + return "the server words the hint differently" + if head == "wait" or path in ("dump.error", "render"): + sentence = lb.get("error") + if isinstance(sentence, str) and sentence != _failure(cb).get("detail"): + if path in ("dump.error", "render") or rest in _MESSAGE_PATHS: + return "the failed run's sentence: the newer shape's `failure.detail` is worded differently" + if path in ("dump.hint", "wait.hint") and lb.get("hint", "") != _failure(cb).get("hint", ""): + return "the newer shape carries a hint the original did not" + if path.startswith("wait.payload.") and name.startswith("verify__status_needs_input"): + return "LenzNeedsInputError.payload is the status as sent (model_dump)" + if path == "dump.chain_id" and "chain_id" in lb and "chain_id" not in cb: + return "`chain_id` is not in the newer shape" + if path == "event.task_id" and "task_id" in lb and "task_id" not in cb: + return "review/citecheck webhooks drop `task_id`; the event reads `event_id` there" + if path.startswith("event.result.") and name.startswith("webhook__verification_completed"): + return "`result` is the dict as sent; the newer shape's carries `completed_at`" + return KNOWN_GAPS.get((name, path)) + + +#: Single gaps no rule covers, each with its reason. +KNOWN_GAPS: dict[tuple[str, str], str] = { + ("assess__list_compound_item.json", "dump.claims[0].hint"): ( + "the newer shape sends no hint on a completed row with other claims found" + ), + ("assess__list_compound_item.json", "render"): "the same hint line, printed by the CLI", + ("review__get_assessment_rows_full_fields.json", "dump.claims[0].assessment.hint"): ( + "the newer shape sends no hint on a completed quick check with other claims found" + ), + ("review__get_failed_every_assessment_failed.json", "dump.failure.hint"): "the server words the hint differently", + ("review__get_failed_every_assessment_failed.json", "render"): "the same hint, printed by the CLI", + ("review__get_failed_every_assessment_failed.json", "render_issues"): "the same hint, printed by the CLI", + ("extract__not_a_claim_beside_claims.json", "dump.status"): ( + "the newer shape answers `ready` when claims came back beside a non-claim" + ), + ("verify__list_200.json", "dump.items[1].verification_id"): "the two recordings list different verifications", + ("verify__list_200.json", "dump.items[1].created_at"): "the two recordings list different verifications", + ( + "verify__verification_200_covered.json", + "dump.coverage.certificate_id", + ): "the two recordings issued different certificates", + ( + "verify__verification_200_covered.json", + "dump.coverage.certificate_url", + ): "the two recordings issued different certificates", + ("review__get_completed_issues_all_verified.json", "dump.claims[1].verification.task_id"): ( + "the two recordings ran different tasks" + ), + ( + "review__get_completed_issues_full.json", + "dump.claims[2].verification.task_id", + ): "the two recordings ran different tasks", +} + + +def _expected(name: str) -> dict[str, Any]: + return json.loads((EXPECTED / name).read_text()) + + +def _diff(a: Any, b: Any, path: str = "") -> list[tuple[str, Any, Any]]: + if isinstance(a, dict) and isinstance(b, dict): + out: list[tuple[str, Any, Any]] = [] + for key in sorted(set(a) | set(b)): + out += _diff(a.get(key, MISSING), b.get(key, MISSING), f"{path}.{key}" if path else key) + return out + if isinstance(a, list) and isinstance(b, list) and len(a) == len(b): + out = [] + for i, (x, y) in enumerate(zip(a, b, strict=True)): + out += _diff(x, y, f"{path}[{i}]") + return out + return [] if a == b else [(path, a, b)] + + +#: Attributes this release added to the webhook events. Everything else on an +#: event must read exactly as before. +NEW_EVENT_ATTRS = {"event_id", "failure", "reason", "claims"} + + +def _old_event_attrs(observed: dict[str, Any], expected: dict[str, Any]) -> dict[str, Any]: + if "event" not in observed: + return observed + event = observed["event"] + added = set(event) - set(expected["event"]) + assert added <= NEW_EVENT_ATTRS, added + return {**observed, "event": {k: v for k, v in event.items() if k in expected["event"]}} + + +@pytest.mark.parametrize("name", names()) +def test_original_shape_is_unchanged(name: str) -> None: + expected = _expected(name) + assert _old_event_attrs(observe(name, load("legacy", name)), expected) == expected + + +def _canonical_view(name: str, expected: dict[str, Any]) -> dict[str, Any]: + fixture = load("canonical", name) + got = _old_event_attrs(observe(name, fixture), expected) + view = {k: v for k, v in got.items() if k not in ("dump", "render_json")} + if "dump" in expected: + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + model = _model_for(name).model_validate(fixture["body"]) + view["dump"] = attr_view(model, expected["dump"]) + returned = expected.get("wait", {}).get("returned") + if returned is not None: + # ``wait`` returns the polled result: read it by attribute too. + view["wait"] = {"returned": attr_view(model.result, returned)} + return view + + +def _canonical_names() -> list[str]: + return [n for n in names() if (FIXTURES / "canonical" / n).exists()] + + +@pytest.mark.parametrize("name", _canonical_names()) +def test_newer_shape_reads_the_same(name: str) -> None: + expected = {k: v for k, v in _expected(name).items() if k != "render_json"} + got = _canonical_view(name, expected) + legacy, canonical = load("legacy", name), load("canonical", name) + gaps = [ + (path, old, new) for path, old, new in _diff(expected, got) if _allowed(name, path, legacy, canonical) is None + ] + assert not gaps, "\n".join(f"{path}: {old!r} -> {new!r}" for path, old, new in gaps) + + +def test_every_known_gap_is_still_a_gap() -> None: + """A listed gap that closed is stale: drop it, so the list stays exact.""" + stale = [] + for (name, path), _reason in KNOWN_GAPS.items(): + expected = {k: v for k, v in _expected(name).items() if k != "render_json"} + if path not in {p for p, _, _ in _diff(expected, _canonical_view(name, expected))}: + stale.append((name, path)) + assert not stale + + +# ── Request bodies ────────────────────────────────────────────────────────── + + +def test_request_bodies_match_the_previous_release() -> None: + """/review and /citecheck keep every body byte for byte, ``webhook_url`` + included in all three states (on those endpoints ``""`` means no webhook, + so it must still be sent). A /verify or /verify/batch call with a webhook + URL is unchanged too.""" + from parity_requests import bodies + + assert bodies() == json.loads((FIXTURES / "requests.json").read_text()) diff --git a/tests/test_read_both_shapes.py b/tests/test_read_both_shapes.py new file mode 100644 index 0000000..0b3db5f --- /dev/null +++ b/tests/test_read_both_shapes.py @@ -0,0 +1,369 @@ +"""The new attributes read the same from either response shape, and the old +ones keep their meaning. ``test_parity.py`` holds the old attributes to the +previous release's output; this file checks the new ones.""" + +from __future__ import annotations + +import json +import warnings + +import pytest +import respx +from parity_observe import load + +from lenz_io import Lenz +from lenz_io.client import DEFAULT_BASE_URL +from lenz_io.errors import LenzPipelineError, LenzRateLimitError, LenzValidationError, map_response_to_error +from lenz_io.models import ( + AssessClaim, + AssessResponse, + BatchAccepted, + ExtractedClaims, + FailureBlock, + ReviewFull, + TaskAccepted, + TaskStatus, + Usage, + Verification, + VerificationList, +) +from lenz_io.webhooks import ( + CitecheckEvent, + ReviewEvent, + VerificationCompleted, + VerificationFailed, + VerificationNeedsInput, + parse_webhook, +) + +pytestmark = pytest.mark.filterwarnings("error::DeprecationWarning") + + +def _both(name: str) -> tuple[dict, dict]: + return load("legacy", name)["body"], load("canonical", name)["body"] + + +# ── /extract ── + + +@pytest.mark.parametrize( + "name", + [ + "extract__ready_one_claim.json", + "extract__ready_several_claims.json", + "extract__locate_true.json", + "extract__locate_some_dropped.json", + "extract__url_input_located.json", + "extract__no_match_with_focus.json", + "extract__not_a_claim.json", + ], +) +def test_extract_claims_reads_the_same_from_both_shapes(name): + legacy, canonical = (ExtractedClaims.model_validate(b) for b in _both(name)) + assert [c.model_dump() for c in legacy.claims] == [c.model_dump() for c in canonical.claims] + assert legacy.status == canonical.status # "not_a_claim" from either spelling + + +def test_extract_one_claim_is_a_list_of_one(): + legacy, canonical = (ExtractedClaims.model_validate(b) for b in _both("extract__ready_one_claim.json")) + assert [c.claim for c in legacy.claims] == [c.claim for c in canonical.claims] == ["Alpha rose 5% in 2024."] + assert canonical.identified_claims == [] and canonical.claim == "Alpha rose 5% in 2024." + + +def test_extract_claims_union_keeps_the_primary_from_an_older_server(): + out = ExtractedClaims.model_validate({"status": "ready", "claim": "A.", "identified_claims": ["B.", "C."]}) + assert [c.claim for c in out.claims] == ["A.", "B.", "C."] + + +def test_extract_empty_claims_does_not_fall_back_to_old_fields(): + out = ExtractedClaims.model_validate({"status": "no_match", "claims": [], "claim": "stale"}) + assert out.claims == [] and out.claim == "stale" + + +# ── /assess ── + + +def test_assess_failed_rows_from_both_shapes(): + legacy, canonical = (AssessResponse.model_validate(b) for b in _both("assess__list_mixed_rows.json")) + for resp in (legacy, canonical): + assert resp.status == "ok" + assert [r.status for r in resp.claims] == ["completed", "failed", "failed", "failed"] + assert [r.failure.code if r.failure else None for r in resp.claims] == [ + None, + "no_checkable_claim", + "upstream_unavailable", + "framing_failed", + ] + assert resp.claims[1].failure.hint.startswith("The input is a greeting.") + # the newer shape: no verdict on a failed row, read as the original "Error"/"low" + row = canonical.claims[1] + assert (row.verdict, row.confidence, row.error_code) == ("Error", "low", "no_claim") + + +def test_assess_single_no_claim_from_both_shapes(): + legacy, canonical = (AssessResponse.model_validate(b) for b in _both("assess__single_no_claim.json")) + for resp in (legacy, canonical): + assert resp.status == "no_checkable_claim" + assert resp.failure is not None and resp.failure.code == "no_checkable_claim" + assert resp.error_code == "no_claim" and resp.error + + +def test_assess_more_claims_on_a_row_from_both_shapes(): + legacy, canonical = (AssessResponse.model_validate(b) for b in _both("assess__list_compound_item.json")) + assert legacy.claims[0].more_claims == canonical.claims[0].more_claims == ["Second claim.", "Third claim."] + assert canonical.claims[0].identified_claims == ["Second claim.", "Third claim."] + + +def test_assess_empty_more_claims_does_not_fall_back(): + row = AssessClaim.model_validate({"claim": "x", "status": "completed", "verdict": "True", "more_claims": []}) + assert row.more_claims == [] and row.identified_claims == [] + row = AssessClaim.model_validate( + {"claim": "x", "verdict": "True", "more_claims": [], "identified_claims": ["stale"]} + ) + assert row.more_claims == [] + + +@pytest.mark.parametrize( + ("rows", "status"), + [ + ([{"verdict": "Error", "error_code": "no_claim"}] * 2, "no_checkable_claim"), + ([{"verdict": "Error", "error_code": "timeout"}], "error"), + ([{"verdict": "Error", "error_code": "timeout"}, {"verdict": "True"}], "ok"), + ], +) +def test_assess_status_is_computed_for_the_original_shape(rows, status): + assert AssessResponse.model_validate({"claims": rows, "error": None}).status == status + + +# ── /verify ── + + +def test_receipt_claim_from_both_shapes(): + legacy, canonical = (BatchAccepted.model_validate(b) for b in _both("verify__batch_202.json")) + assert ( + [i.claim for i in legacy.items] == [i.claim for i in canonical.items] == [i.claim_text for i in canonical.items] + ) + assert TaskAccepted.model_validate({"task_id": "t"}).claim == "" + + +@pytest.mark.parametrize( + "name", + [ + "verify__status_failed.json", + "verify__status_failed_retryable.json", + "verify__status_not_a_claim.json", + "verify__status_cancelled_after_a_while.json", + ], +) +def test_failed_status_failure_block_from_both_shapes(name): + legacy, canonical = (TaskStatus.model_validate(b) for b in _both(name)) + for st in (legacy, canonical): + assert st.failure is not None + assert st.failure.code == _both(name)[1]["failure"]["code"] + assert st.failure.failure_class == canonical.failure_class + assert st.failure.retryable is canonical.retryable + assert st.failure.detail + assert canonical.failure_reason == legacy.failure_reason + assert canonical.error == canonical.failure.detail + + +def test_needs_input_options_from_both_shapes(): + legacy, canonical = (TaskStatus.model_validate(b) for b in _both("verify__status_needs_input.json")) + assert [c.claim for c in legacy.claims] == [c.claim for c in canonical.claims] + assert [c.text for c in canonical.claims] == [c.claim for c in canonical.claims] + + +def test_completed_at_and_the_original_modified_at_rule(): + late, early = "2026-10-01T23:55:00+00:00", "2026-10-02T00:03:00+00:00" + crossed = Verification.model_validate({"created_at": late, "completed_at": early}) + assert crossed.modified_at == early + same_day = Verification.model_validate({"created_at": "2026-10-01T08:00:00Z", "completed_at": "2026-10-01T20:00Z"}) + assert same_day.modified_at is None and same_day.completed_at == "2026-10-01T20:00Z" + # a UTC calendar day, whatever offset the strings carry + offset = Verification.model_validate( + {"created_at": "2026-10-01T22:00:00+00:00", "completed_at": "2026-10-02T01:00:00+02:00"} + ) + assert offset.modified_at is None + legacy = Verification.model_validate({"created_at": late, "modified_at": early}) + assert legacy.completed_at == early + assert Verification.model_validate({"created_at": late, "modified_at": None}).completed_at is None + + +@pytest.mark.parametrize( + "name", + [ + "verify__verification_200_modified_at_crosses_midnight_by_minutes.json", + "verify__verification_200_modified_at_same_day_hours_apart.json", + "verify__list_200_modified_at_crosses_midnight_by_minutes.json", + ], +) +def test_modified_at_from_both_shapes(name): + cls = VerificationList if "list" in name else Verification + legacy, canonical = (cls.model_validate(b) for b in _both(name)) + pick = (lambda m: m.items[0]) if cls is VerificationList else (lambda m: m) + assert pick(legacy).modified_at == pick(canonical).modified_at + + +# ── /me/usage ── + + +@pytest.mark.parametrize( + "name", + ["account__me_usage_pro_extra.json", "account__me_usage_free_partly_spent.json", "account__me_usage_free.json"], +) +def test_usage_blocks_are_computed_from_the_pool(name): + legacy, canonical = (Usage.model_validate(b) for b in _both(name)) + for cap in ("verify", "ask", "assess"): + assert getattr(legacy, cap).model_dump() == getattr(canonical, cap).model_dump() + assert canonical.quota_resets_at == canonical.credits.resets_at + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + assert canonical.credits.bonus == legacy.credits.bonus + + +# ── /review ── + + +@pytest.mark.parametrize( + "name", + [ + "review__get_more_claims.json", + "review__get_claim_limit_reached_exact.json", + "review__get_citations_limit_reached.json", + "review__get_completed_issues_full.json", + "review__get_assessment_rows_full_fields.json", + ], +) +def test_review_new_names_from_both_shapes(name): + legacy, canonical = (ReviewFull.model_validate(b) for b in _both(name)) + assert legacy.summary.claim_limit_exceeded == canonical.summary.claim_limit_exceeded + assert legacy.summary.citation_limit_exceeded == canonical.summary.citation_limit_exceeded + for a, b in zip(legacy.claims, canonical.claims, strict=True): + assert a.assessment.more_claims == b.assessment.more_claims + if a.assessment.failure is not None: + assert a.assessment.failure.code == b.assessment.failure.code + + +def test_review_failure_code_reads_the_new_spelling(): + legacy, canonical = (ReviewFull.model_validate(b) for b in _both("review__get_failed_no_claim.json")) + assert legacy.failure.code == canonical.failure.code == "no_checkable_claim" + assert canonical.failure.failure_reason == "no_claim" + assert FailureBlock.model_validate({"failure_reason": "not_a_claim"}).code == "no_checkable_claim" + + +# ── dumps show what was sent ── + + +def test_model_dump_shows_the_newer_shape_as_sent(): + canonical = load("canonical", "assess__list_mixed_rows.json")["body"] + assert AssessResponse.model_validate(canonical).model_dump(mode="json") == canonical + canonical = load("canonical", "verify__batch_202.json")["body"] + assert BatchAccepted.model_validate(canonical).model_dump(mode="json") == canonical + + +# ── webhooks ── + + +@pytest.mark.parametrize( + "name", + [ + "webhook__verification_failed_not_a_claim.json", + "webhook__verification_failed_upstream_unavailable.json", + ], +) +def test_failed_webhook_from_both_shapes(name): + legacy, canonical = (parse_webhook(b) for b in _both(name)) + assert isinstance(legacy, VerificationFailed) and isinstance(canonical, VerificationFailed) + assert legacy.error == canonical.error + assert legacy.failure.code == canonical.failure.code + assert (legacy.failure_class, legacy.retryable) == (canonical.failure_class, canonical.retryable) + assert canonical.event_id + + +def test_needs_input_webhook_from_both_shapes(): + legacy, canonical = (parse_webhook(b) for b in _both("webhook__verification_needs_input_multi_claim.json")) + assert isinstance(canonical, VerificationNeedsInput) + assert legacy.needs_input == canonical.needs_input + assert [c.claim for c in legacy.claims] == [c.claim for c in canonical.claims] + assert legacy.reason == canonical.reason == "multi_claim" + + +def test_completed_webhook_result_from_both_shapes(): + name = "webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json" + legacy, canonical = (parse_webhook(b) for b in _both(name)) + assert isinstance(canonical, VerificationCompleted) + assert legacy.verification_id == canonical.verification_id + assert legacy.result["modified_at"] == canonical.result["modified_at"] + + +@pytest.mark.parametrize("name", ["webhook__review_completed.json", "webhook__citecheck_completed.json"]) +def test_review_webhook_without_task_id_reads_event_id(name): + canonical = parse_webhook(load("canonical", name)["body"]) + assert isinstance(canonical, (ReviewEvent, CitecheckEvent)) + assert canonical.task_id == canonical.event_id != "" + + +# ── errors ── + + +def test_409_failed_run_reads_the_failure_block(): + _, canonical = _both("verify__verification_failed_409.json") + err = map_response_to_error(409, json.dumps(canonical).encode()) + assert isinstance(err, LenzPipelineError) + assert (err.failure_reason, err.failure_class, err.retryable) == ( + "research_empty", + "insufficient_evidence", + False, + ) + _, canonical = _both("verify__verification_failed_409_not_a_claim_after_a_while.json") + assert map_response_to_error(409, json.dumps(canonical).encode()).failure_reason == "not_a_claim" + + +def test_validation_errors_from_both_shapes(): + legacy, canonical = _both("errors__validation_wrong_type.json") + for body in (legacy, canonical): + err = map_response_to_error(422, json.dumps(body).encode()) + assert isinstance(err, LenzValidationError) + assert [e["msg"] for e in err.errors] == ["Input should be a valid string"] + + +def test_rate_limit_wait_from_both_shapes(): + for body in _both("errors__rate_limited_extract.json"): + err = map_response_to_error(429, json.dumps(body).encode()) + assert isinstance(err, LenzRateLimitError) + assert (err.retry_after, err.reset_in_seconds) == (900, 900) + err = map_response_to_error(429, json.dumps({"code": "review_in_flight", "retry_after": 0}).encode()) + assert (err.retry_after, err.reset_in_seconds) == (0, None) + + +def test_quota_remaining_is_derived_when_absent(): + legacy, canonical = _both("citecheck__402_no_credits.json") + assert map_response_to_error(402, json.dumps(canonical).encode()).remaining == 100 + assert map_response_to_error(402, json.dumps(legacy).encode()).remaining == 100 + + +# ── requests ── + + +def _sent(call) -> dict: + with respx.mock(base_url=DEFAULT_BASE_URL, assert_all_called=False) as mock: + verify = mock.post("/verify").respond(202, json={"task_id": "t"}) + batch = mock.post("/verify/batch").respond(202, json={"batch_id": "b", "items": []}) + client = Lenz(api_key="lenz_" + "0" * 32) + call(client) + route = verify if verify.called else batch + return json.loads(route.calls.last.request.content) + + +@pytest.mark.parametrize("webhook_url", [None, ""]) +def test_verify_never_sends_an_empty_webhook_url(webhook_url): + kwargs = {} if webhook_url is None else {"webhook_url": webhook_url} + assert "webhook_url" not in _sent(lambda c: c._verify_submit(claim="x", **kwargs)) + assert "webhook_url" not in _sent(lambda c: c.verify_batch(claims=[{"claim": "x"}], **kwargs)) + item = _sent(lambda c: c.verify_batch(claims=[{"claim": "x", "webhook_url": ""}]))["claims"][0] + assert "webhook_url" not in item + + +def test_verify_sends_a_webhook_url_that_was_set(): + body = _sent(lambda c: c.verify("x", webhook_url="https://hooks.example.test/x")) + assert body["webhook_url"] == "https://hooks.example.test/x" diff --git a/tests/test_usage_models.py b/tests/test_usage_models.py index 697ad32..b54604e 100644 --- a/tests/test_usage_models.py +++ b/tests/test_usage_models.py @@ -118,13 +118,13 @@ def test_capability_blocks_are_projections_of_the_one_pool(): def test_reading_the_credits_alias_warns_and_returns_bonus(): cap = UsageCapacity.model_validate(POOL_PAYLOAD["verify"]) assert cap.bonus == 20 - with pytest.deprecated_call(match="2026-11-29"): + with pytest.deprecated_call(match="is deprecated;"): assert cap.credits == 20 def test_dumping_keeps_the_alias_and_does_not_warn(): """Serialization must stay warning-free — a `--json` dump of usage is not - a deprecated read, and the key stays on the wire until 2026-11-29.""" + a deprecated read, and the key stays on the wire for existing callers.""" cap = UsageCapacity.model_validate(POOL_PAYLOAD["verify"]) with warnings.catch_warnings(): warnings.simplefilter("error", DeprecationWarning) @@ -144,7 +144,7 @@ def test_old_server_sending_only_credits_still_fills_bonus(): def test_server_after_the_alias_removal_still_fills_credits(): - """After 2026-11-29 the server drops `credits`; the alias keeps reading.""" + """A response without `credits` (a computed block) still reads the alias.""" cap = UsageCapacity.model_validate( {"quota_used": 13, "quota_total": 520, "quota_remaining": 507, "bonus": 20, "remaining": 507} ) @@ -173,13 +173,13 @@ def test_pre_pool_server_leaves_the_balance_empty_not_wrong(): def test_reading_the_bonus_alias_warns_and_returns_extra(): c = UsageCredits.model_validate(POOL_PAYLOAD["credits"]) assert c.extra == 200 - with pytest.deprecated_call(match="2026-11-29"): + with pytest.deprecated_call(match="is deprecated;"): assert c.bonus == 200 def test_dumping_the_pool_keeps_bonus_and_does_not_warn(): """A `--json` dump is not a deprecated read, and the key stays on the wire - until 2026-11-29.""" + for existing callers.""" c = UsageCredits.model_validate(POOL_PAYLOAD["credits"]) with warnings.catch_warnings(): warnings.simplefilter("error", DeprecationWarning) @@ -193,7 +193,7 @@ def test_a_server_sending_only_bonus_still_fills_extra(): def test_a_server_sending_only_extra_still_fills_bonus(): - """After 2026-11-29 the server sends only `extra`; `bonus` keeps reading.""" + """The newer response shape sends only `extra`; `bonus` keeps reading.""" c = UsageCredits.model_validate({"total": 300, "used": 0, "remaining": 300, "extra": 200}) assert c.extra == 200 with pytest.deprecated_call(): From 8629e5068b9a89c7d21b0a3c1c1b7cc81d56830b Mon Sep 17 00:00:00 2001 From: Kosta Date: Thu, 8 Oct 2026 20:08:25 +0300 Subject: [PATCH 2/5] fix: match the Node SDK: identical openapi.json text, an empty task_id on newer-shape review webhooks Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 4 +++- openapi.json | 8 ++++---- src/lenz_io/webhooks.py | 12 +++++------- tests/test_parity.py | 8 +++++++- tests/test_read_both_shapes.py | 4 ++-- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17abab8..ff7870a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,9 @@ on upgrade. `claim_limit_exceeded` and `citation_limit_exceeded`; `CitecheckSummary.citation_limit_exceeded`. - Webhooks: `event_id` on every event, `VerificationFailed.failure`, - `VerificationNeedsInput.reason` and `.claims`. `parse_webhook` and + `VerificationNeedsInput.reason` and `.claims`. A review or citation-check + event in the newer shape carries no `task_id` (it reads `""`; deduplicate + on `event_id`, as before). `parse_webhook` and `LenzWebhooks.parse` read the newer envelope too (`event`, `event_id`, the work's id, `status`, and the polled body under `verification` / `review` / `citecheck`). diff --git a/openapi.json b/openapi.json index 97c8a8b..925314c 100644 --- a/openapi.json +++ b/openapi.json @@ -411,7 +411,7 @@ } } }, - "description": "Return the calling account's credit balance and what it can still buy.\n\n**``credits`` is the balance.** One pool funds every billable capability,\nat the weights in ``costs`` \u2014 today ``verify`` 10, ``assess`` 1, ``ask`` 1.\nIt has two buckets: the monthly allowance for the current ``plan``, which\nresets at ``resets_at``, and non-expiring ``extra`` credits from grants and\ntop-ups, spent only once the allowance is gone. ``remaining`` is the sum,\nand is what a call is actually checked against.\n\n``credits.bonus`` is the deprecated old name of ``credits.extra``, the same\nnumber, deprecated with the fields below and kept for existing callers. Read ``extra``.\n\n``plan`` is the stable slug to branch on; ``plan_label`` is the same tier\nas display copy (\"Pro\"). Two fields rather than one humanised\nstring, so a reworded label cannot break a client comparing tiers.\nThe Pro plan's ``plan`` is ``pro``; it read ``developer`` before\n2026-09-15 (#664), while ``plan_label`` already read \"Pro\".\n\n**The per-capability blocks are deprecated.** ``verify`` / ``ask`` /\n``assess`` are **projections** of that one pool into each capability's own\nunit \u2014 \"how many of these could I still make\" \u2014 not separate allowances.\nSpending on one moves all of them, and they are floor divisions, so a\nverify block ticks once per 10 credits spent anywhere.\n\nThey are deprecated, together with the per-block ``credits`` alias, and\nkept for existing callers. Derive them instead::\n\n remaining = credits.remaining // costs[capability]\n total = credits.total // costs[capability]\n used = total - remaining\n\nTwo capabilities at the same price emit identical blocks \u2014 ``ask`` and\n``assess`` are both 1 credit \u2014 which is the clearest sign the shape\ndescribes an allowance that no longer exists.\n\n``bonus`` in each block is ``credits.extra`` in that capability's unit. The\nolder key ``credits`` is its deprecated alias, on the same date.\n\n``costs`` is one entry per capability at its DEFAULT price. Prices that\ndepend on a request parameter live in ``cost_options``, nested capability\n\u2192 parameter \u2192 value \u2014 ``{\"verify\": {\"depth\": {\"standard\": 10, \"low\": 5}}}``.\nTwo maps rather than a flat one with a ``verify_low`` key, so a future\ntuning parameter nests instead of adding an entry that reads like a fifth\ncapability. Every capability in ``cost_options`` also appears in ``costs``\nat its default, so reading only ``costs`` is always correct.\n\n``extract`` is free at the pool (``costs.extract`` is 0) and is bounded by\na per-account daily fair-use cap instead, reported separately here and\nrejected with 429 rather than 402.", + "description": "Return the calling account's credit balance and what it can still buy.\n\n**``credits`` is the balance.** One pool funds every billable capability,\nat the weights in ``costs`` \u2014 today ``verify`` 10, ``assess`` 1, ``ask`` 1.\nIt has two buckets: the monthly allowance for the current ``plan``, which\nresets at ``resets_at``, and non-expiring ``extra`` credits from grants and\ntop-ups, spent only once the allowance is gone. ``remaining`` is the sum,\nand is what a call is actually checked against.\n\n``credits.bonus`` is the deprecated old name of ``credits.extra``, the same\nnumber, kept for existing callers with the fields below. Read ``extra``.\n\n``plan`` is the stable slug to branch on; ``plan_label`` is the same tier\nas display copy (\"Pro\"). Two fields rather than one humanised\nstring, so a reworded label cannot break a client comparing tiers.\nThe Pro plan's ``plan`` is ``pro``; it read ``developer`` before\n2026-09-15 (#664), while ``plan_label`` already read \"Pro\".\n\n**The per-capability blocks are deprecated.** ``verify`` / ``ask`` /\n``assess`` are **projections** of that one pool into each capability's own\nunit \u2014 \"how many of these could I still make\" \u2014 not separate allowances.\nSpending on one moves all of them, and they are floor divisions, so a\nverify block ticks once per 10 credits spent anywhere.\n\nThey are kept for existing callers, with the per-block ``credits`` alias.\nNew code derives them instead::\n\n remaining = credits.remaining // costs[capability]\n total = credits.total // costs[capability]\n used = total - remaining\n\nTwo capabilities at the same price emit identical blocks \u2014 ``ask`` and\n``assess`` are both 1 credit \u2014 which is the clearest sign the shape\ndescribes an allowance that no longer exists.\n\n``bonus`` in each block is ``credits.extra`` in that capability's unit. The\nolder key ``credits`` is its deprecated alias, on the same date.\n\n``costs`` is one entry per capability at its DEFAULT price. Prices that\ndepend on a request parameter live in ``cost_options``, nested capability\n\u2192 parameter \u2192 value \u2014 ``{\"verify\": {\"depth\": {\"standard\": 10, \"low\": 5}}}``.\nTwo maps rather than a flat one with a ``verify_low`` key, so a future\ntuning parameter nests instead of adding an entry that reads like a fifth\ncapability. Every capability in ``cost_options`` also appears in ``costs``\nat its default, so reading only ``costs`` is always correct.\n\n``extract`` is free at the pool (``costs.extract`` is 0) and is bounded by\na per-account daily fair-use cap instead, reported separately here and\nrejected with 429 rather than 402.", "tags": [ "Account" ], @@ -2510,7 +2510,7 @@ "type": "object" }, "MeUsageCreditsOut": { - "description": "The account's credit balance \u2014 the one pool every capability spends.\n\nTwo buckets: the monthly allowance for the current plan (resets at\n``resets_at``) and non-expiring ``extra`` credits from grants and top-ups,\nwhich are spent only once the allowance is gone. ``remaining`` is the sum\nand is what a call is checked against.\n\n``bonus`` is a DEPRECATED alias of ``extra`` (the balance's name until\n2026-09-15), deprecated with the other deprecated fields on this endpoint and kept\nfor existing callers. It was renamed because the balance holds top-ups you paid for as\nwell as grants.", + "description": "The account's credit balance \u2014 the one pool every capability spends.\n\nTwo buckets: the monthly allowance for the current plan (resets at\n``resets_at``) and non-expiring ``extra`` credits from grants and top-ups,\nwhich are spent only once the allowance is gone. ``remaining`` is the sum\nand is what a call is checked against.\n\n``bonus`` is a DEPRECATED alias of ``extra`` (the balance's name until\n2026-09-15), kept for existing callers with the other deprecated fields on\nthis endpoint. It was renamed because the balance holds top-ups you paid for as\nwell as grants.", "properties": { "total": { "default": 0, @@ -2576,7 +2576,7 @@ "type": "object" }, "MeUsageOut": { - "description": "The calling account's credit balance, and what it can still buy.\n\n``credits`` is the balance and ``costs`` is the price list. Those two,\nplus ``cost_options``, are the whole contract for a new integration.\n\nThe ``verify`` / ``ask`` / ``assess`` blocks are DEPRECATED projections of\nthat same pool into each capability's unit, kept for clients\nalready reading them.\n\n``extract`` is free at the pool (``costs.extract`` is 0) and carries a\nper-account daily fair-use cap instead; it rejects with 429, not 402.\n\nThe Pro plan's ``plan`` is ``pro`` since 2026-09-15; it was ``developer``\nbefore (#664). ``plan_label`` reads \"Pro\" either way.", + "description": "The calling account's credit balance, and what it can still buy.\n\n``credits`` is the balance and ``costs`` is the price list. Those two,\nplus ``cost_options``, are the whole contract for a new integration.\n\nThe ``verify`` / ``ask`` / ``assess`` blocks are DEPRECATED projections of\nthat same pool into each capability's unit, kept for\nclients already reading them.\n\n``extract`` is free at the pool (``costs.extract`` is 0) and carries a\nper-account daily fair-use cap instead; it rejects with 429, not 402.\n\nThe Pro plan's ``plan`` is ``pro`` since 2026-09-15; it was ``developer``\nbefore (#664). ``plan_label`` reads \"Pro\" either way.", "properties": { "plan": { "default": "free", @@ -2653,7 +2653,7 @@ "type": "object" }, "MeUsageQuotaOut": { - "description": "DEPRECATED. One capability's share of the pool, projected into its unit.\n\n**Deprecated**, with the per-block ``credits`` alias below, and kept for\nexisting callers. Read\n``MeUsageOut.credits`` and ``MeUsageOut.costs`` instead and do the\ndivision \u2014 it is one line, and it is the same one this block does::\n\n remaining = credits.remaining // costs[capability]\n total = credits.total // costs[capability]\n used = total - remaining\n\nThese are **projections, not allowances**. Every billable capability draws\non the single balance in ``MeUsageOut.credits``, at the weight in\n``MeUsageOut.costs``; this block answers \"how many ``/verify`` calls could\nI still make if I spent everything on them\". Spending on any capability\nmoves every block, and the division floors \u2014 a ``verify`` block whose\nweight is 10 ticks once per 10 credits spent anywhere.\n\nThey predate the pool, when each really was its own allowance, and that is\nthe reason to retire them: two capabilities at the same price emit\nbyte-identical objects (``ask`` and ``assess`` are both 1 credit today),\nso the shape suggests a per-capability allowance that no longer exists.\n\n``bonus`` is ``MeUsageOut.credits.extra``, the non-expiring balance, in\nthis capability's unit.\n``quota_used`` is derived as ``quota_total - quota_remaining``, so\n``used + remaining == total`` always holds.\n\n``credits`` is a DEPRECATED alias of ``bonus``, kept for compatibility\nwith existing callers. It never meant the pool \u2014 before the pool existed it\nmeant this capability's one-off top-up balance, which is exactly what\n``bonus`` now reports.", + "description": "DEPRECATED. One capability's share of the pool, projected into its unit.\n\nKept for existing callers, with the per-block ``credits`` alias below. Read\n``MeUsageOut.credits`` and ``MeUsageOut.costs`` instead and do the\ndivision \u2014 it is one line, and it is the same one this block does::\n\n remaining = credits.remaining // costs[capability]\n total = credits.total // costs[capability]\n used = total - remaining\n\nThese are **projections, not allowances**. Every billable capability draws\non the single balance in ``MeUsageOut.credits``, at the weight in\n``MeUsageOut.costs``; this block answers \"how many ``/verify`` calls could\nI still make if I spent everything on them\". Spending on any capability\nmoves every block, and the division floors \u2014 a ``verify`` block whose\nweight is 10 ticks once per 10 credits spent anywhere.\n\nThey predate the pool, when each really was its own allowance, and that is\nthe reason to retire them: two capabilities at the same price emit\nbyte-identical objects (``ask`` and ``assess`` are both 1 credit today),\nso the shape suggests a per-capability allowance that no longer exists.\n\n``bonus`` is ``MeUsageOut.credits.extra``, the non-expiring balance, in\nthis capability's unit.\n``quota_used`` is derived as ``quota_total - quota_remaining``, so\n``used + remaining == total`` always holds.\n\n``credits`` is a DEPRECATED alias of ``bonus``, kept for compatibility\nwith existing callers. It never meant the pool \u2014 before the pool existed it\nmeant this capability's one-off top-up balance, which is exactly what\n``bonus`` now reports.", "properties": { "quota_used": { "default": 0, diff --git a/src/lenz_io/webhooks.py b/src/lenz_io/webhooks.py index c88741b..a28409b 100644 --- a/src/lenz_io/webhooks.py +++ b/src/lenz_io/webhooks.py @@ -212,9 +212,9 @@ class ReviewEvent(WebhookEvent): Deduplicate on ``event_id``: it is the same on every delivery attempt of one event, while ``attempt`` counts up. ``task_id`` (deprecated) - identifies the delivery and cannot be polled on ``/verify/status``; a - payload that does not carry it reads ``event_id`` there. The deep checks a - review runs send no ``verification.*`` events of their own. + identifies the delivery and cannot be polled on ``/verify/status``; it is + ``""`` on a payload that does not carry it (the newer shape). The deep + checks a review runs send no ``verification.*`` events of their own. """ event_id: str = "" @@ -231,8 +231,8 @@ class CitecheckEvent(WebhookEvent): returns), or ``None`` if it could not be parsed (``raw["citecheck"]`` still has it). Deduplicate on ``event_id``: it is the same on every delivery attempt of one event. ``task_id`` (deprecated) identifies the - delivery and cannot be polled on ``/verify/status``; a payload that does - not carry it reads ``event_id`` there. + delivery and cannot be polled on ``/verify/status``; it is ``""`` on a + payload that does not carry it (the newer shape). """ event_id: str = "" @@ -340,7 +340,6 @@ def _build_event(payload: dict[str, Any]) -> WebhookEvent: review = ReviewFull.model_validate(review_body) if isinstance(review_body, dict) else None except ValueError: review = None - common["task_id"] = task_id or event_id return ReviewEvent( **common, review_id=str(payload.get("review_id") or _dict(review_body).get("review_id") or ""), @@ -352,7 +351,6 @@ def _build_event(payload: dict[str, Any]) -> WebhookEvent: check = Citecheck.model_validate(check_body) if isinstance(check_body, dict) else None except ValueError: check = None - common["task_id"] = task_id or event_id return CitecheckEvent( **common, citecheck_id=str(payload.get("citecheck_id") or _dict(check_body).get("citecheck_id") or ""), diff --git a/tests/test_parity.py b/tests/test_parity.py index c5fea40..90a942e 100644 --- a/tests/test_parity.py +++ b/tests/test_parity.py @@ -34,6 +34,12 @@ # # Each gap is allowed only where the two recorded responses themselves differ # in the value it comes from: a rule never excuses a difference the SDK made. +# The categories are the ones the Node SDK allows, so the two behave alike: +# the server's sentences (error / failure text), the codes and field errors it +# sends on a 422, `chain_id`, the review / citation-check webhook `task_id`, +# and a row hint the newer shape does not carry. The single entries in +# ``KNOWN_GAPS`` below fall in those categories too, plus two where the two +# recordings simply hold different ids. #: An exception's text fields: built from the body's ``detail``. _MESSAGE_PATHS = ("message", "cause", "friendly_text", "payload_json.error.message") @@ -74,7 +80,7 @@ def _allowed(name: str, path: str, legacy: dict[str, Any], canonical: dict[str, if path == "dump.chain_id" and "chain_id" in lb and "chain_id" not in cb: return "`chain_id` is not in the newer shape" if path == "event.task_id" and "task_id" in lb and "task_id" not in cb: - return "review/citecheck webhooks drop `task_id`; the event reads `event_id` there" + return "review/citecheck webhooks drop `task_id` (never pollable); dedupe on `event_id`" if path.startswith("event.result.") and name.startswith("webhook__verification_completed"): return "`result` is the dict as sent; the newer shape's carries `completed_at`" return KNOWN_GAPS.get((name, path)) diff --git a/tests/test_read_both_shapes.py b/tests/test_read_both_shapes.py index 0b3db5f..83eee5c 100644 --- a/tests/test_read_both_shapes.py +++ b/tests/test_read_both_shapes.py @@ -297,10 +297,10 @@ def test_completed_webhook_result_from_both_shapes(): @pytest.mark.parametrize("name", ["webhook__review_completed.json", "webhook__citecheck_completed.json"]) -def test_review_webhook_without_task_id_reads_event_id(name): +def test_review_webhook_without_task_id(name): canonical = parse_webhook(load("canonical", name)["body"]) assert isinstance(canonical, (ReviewEvent, CitecheckEvent)) - assert canonical.task_id == canonical.event_id != "" + assert canonical.task_id == "" and canonical.event_id != "" # ── errors ── From 36e40fad0cb94c2356280e10ca9b7da64b7cf8c0 Mon Sep 17 00:00:00 2001 From: Kosta Date: Thu, 8 Oct 2026 20:09:31 +0300 Subject: [PATCH 3/5] docs(changelog): drop the wrong note about idempotency keys from an earlier release Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff7870a..7770c25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,9 +67,7 @@ on upgrade. empty per-item `webhook_url`). The API has always read an empty value there as "use the key's default webhook", the same as leaving it out, so nothing changes now; leaving it out keeps that meaning on later API versions, where - `""` means "no webhook". A retry that reuses an idempotency key from an - earlier release's call sends a different body and is refused as a - different request. `review` and `citecheck` send `webhook_url` exactly as + `""` means "no webhook". `review` and `citecheck` send `webhook_url` exactly as before (there `""` means "no webhook"). - `model_dump()` returns the shape the server sent: attributes filled in from the other shape are left out, so an original-shape response dumps exactly as From 7004e8c1469f303f8b1937a2ea916acc760edf48 Mon Sep 17 00:00:00 2001 From: Kosta Date: Thu, 8 Oct 2026 20:25:40 +0300 Subject: [PATCH 4/5] fix: parse original-shape bodies exactly as 2.20 did; newer names are properties A body is read as the newer response shape only when it carries a key only that shape has; every other body goes through the same fields, values, dump, repr, exclude_unset, JSON schema and pickle as before. The newer names (claims, status, failure, more_claims, completed_at, claim, code, detail, the *_exceeded flags, webhook event_id / failure / claims / reason) are read-only properties, not fields, and the model-level serializer is gone. Errors read the newer failure block, retry_after and a computed remaining only for a newer-shape body and only where the original key is absent. Webhook events keep their dataclass fields; a needs_input option with a null domain no longer raises. The CLI renderers are back to 2.20's code. Parity fixtures are rebuilt from the real recorded pairs (responses and webhooks), extract goes through the client with the recorded locate, and the oracle now also freezes exclude_unset dumps, repr, JSON schemas and pickles. The remaining removal-date text is gone, and the changelog lists what to settle before the SDK asks for the newer shape. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 40 +- README.md | 5 +- openapi.json | 2 +- src/lenz_io/cli/render.py | 30 +- src/lenz_io/cli/verify.py | 8 +- src/lenz_io/client.py | 30 +- src/lenz_io/errors.py | 42 +- src/lenz_io/models.py | 980 +- src/lenz_io/webhooks.py | 313 +- .../parity/canonical/account__api_root.json | 43 + .../account__ask_history_after_reset.json | 14 + .../account__ask_history_after_send.json | 25 + .../canonical/account__ask_history_empty.json | 14 + .../account__ask_history_messages.json | 25 + .../parity/canonical/account__ask_reset.json | 11 + .../parity/canonical/account__ask_send.json | 13 + .../canonical/account__ask_send_language.json | 13 + .../canonical/account__library_empty.json | 10 +- ...dified_at_crosses_midnight_by_minutes.json | 10 +- ...item_modified_at_same_day_hours_apart.json | 10 +- .../canonical/account__library_items.json | 26 +- .../canonical/account__library_no_match.json | 10 +- .../account__library_page_past_end.json | 10 +- ...ccount__library_paginated_second_page.json | 20 +- .../account__me_usage_extra_credits.json | 12 +- .../account__me_usage_extra_only.json | 12 +- .../account__me_usage_extract_calls.json | 12 +- .../canonical/account__me_usage_free.json | 12 +- .../account__me_usage_free_partly_spent.json | 12 +- .../canonical/account__me_usage_oauth.json | 40 + .../canonical/account__me_usage_plus.json | 12 +- .../canonical/account__me_usage_pro.json | 12 +- .../account__me_usage_pro_extra.json | 12 +- .../account__me_usage_stale_quota_row.json | 12 +- .../account__oauth_register_success.json | 25 + .../canonical/account__oauth_revoke.json | 9 + .../account__oauth_revoke_token.json | 9 + .../account__webhook_secret_api_key.json | 12 + ...nt__webhook_secret_insufficient_scope.json | 14 + .../account__webhook_secret_oauth.json | 11 + .../parity/canonical/assess__401_no_key.json | 8 +- .../canonical/assess__402_no_credits.json | 12 +- .../canonical/assess__422_blank_item.json | 10 +- .../canonical/assess__422_blank_text.json | 10 +- .../canonical/assess__422_input_conflict.json | 10 +- .../canonical/assess__422_item_too_long.json | 10 +- .../canonical/assess__422_no_input_field.json | 10 +- .../canonical/assess__422_too_many_items.json | 10 +- .../assess__422_wrong_type_claim.json | 10 +- .../assess__422_wrong_type_claims.json | 10 +- .../canonical/assess__502_framing_failed.json | 8 +- .../canonical/assess__503_capacity.json | 12 +- ...ss__503_list_all_upstream_unavailable.json | 12 +- .../assess__503_upstream_unavailable.json | 12 +- .../canonical/assess__deep_tier_hit.json | 10 +- .../assess__idempotency_body_mismatch.json | 8 +- .../canonical/assess__idempotency_first.json | 10 +- .../canonical/assess__idempotency_replay.json | 10 +- .../assess__list_all_error_rows.json | 10 +- .../canonical/assess__list_compound_item.json | 10 +- .../canonical/assess__list_mixed_rows.json | 10 +- .../parity/canonical/assess__memo_hit.json | 10 +- .../canonical/assess__replay_later_200.json | 10 +- .../canonical/assess__single_no_claim.json | 10 +- .../canonical/assess__single_one_claim.json | 10 +- ...ss__single_text_over_wave_more_claims.json | 10 +- .../assess__single_text_several_claims.json | 10 +- .../canonical/assess__suggest_rewrite.json | 10 +- .../canonical/citecheck__402_no_credits.json | 12 +- .../canonical/citecheck__422_empty_body.json | 10 +- .../canonical/citecheck__422_invalid_doi.json | 10 +- .../citecheck__422_max_citations_over_20.json | 10 +- ...techeck__422_max_citations_with_pairs.json | 10 +- .../citecheck__422_pair_bad_url_scheme.json | 10 +- .../citecheck__422_pair_no_source.json | 10 +- .../citecheck__422_pair_url_and_doi.json | 10 +- .../canonical/citecheck__422_pairs_empty.json | 10 +- .../citecheck__422_pairs_over_20.json | 10 +- ...citecheck__422_quote_not_in_statement.json | 10 +- .../citecheck__422_text_and_pairs.json | 10 +- .../citecheck__422_unknown_field.json | 10 +- .../canonical/citecheck__422_url_input.json | 10 +- ...citecheck__422_webhook_secret_missing.json | 22 + .../citecheck__429_citecheck_in_flight.json | 10 +- .../canonical/citecheck__503_capacity.json | 12 +- .../citecheck__503_citations_unavailable.json | 12 +- .../citecheck__get_404_not_found.json | 8 +- .../citecheck__get_404_review_id.json | 8 +- .../canonical/citecheck__get_410_purged.json | 10 +- .../canonical/citecheck__get_checking.json | 12 +- .../citecheck__get_completed_clean.json | 14 +- .../citecheck__get_completed_doi_pair.json | 14 +- .../citecheck__get_completed_incomplete.json | 14 +- ...citecheck__get_completed_issues_found.json | 14 +- ...check__get_completed_partly_supported.json | 14 +- .../citecheck__get_completed_unchecked.json | 14 +- .../citecheck__get_failed_no_citations.json | 14 +- ...heck__get_failed_upstream_unavailable.json | 14 +- .../canonical/citecheck__get_queued.json | 12 +- ...heck__get_text_limit_exactly_at_limit.json | 14 +- .../citecheck__get_text_limit_reached.json | 14 +- ...echeck__idempotency_body_mismatch_422.json | 8 +- .../citecheck__idempotency_conflict_409.json | 10 +- .../citecheck__idempotent_replay_202.json | 8 +- .../canonical/citecheck__receipt_202.json | 8 +- ...echeck__receipt_202_empty_webhook_url.json | 8 +- .../canonical/errors__ask_bad_language.json | 10 +- .../canonical/errors__ask_empty_message.json | 10 +- .../parity/canonical/errors__ask_failed.json | 8 +- .../errors__ask_idempotency_key_reused.json | 8 +- .../errors__ask_message_too_long.json | 10 +- .../canonical/errors__ask_not_completed.json | 8 +- .../errors__ask_reset_not_found.json | 8 +- .../canonical/errors__ask_send_not_found.json | 8 +- .../canonical/errors__auth_bad_key.json | 8 +- .../errors__auth_bad_oauth_token.json | 13 + .../canonical/errors__auth_basic_scheme.json | 8 +- .../errors__auth_expired_oauth_token.json | 13 + .../errors__auth_insufficient_scope.json | 10 +- .../errors__auth_missing_bearer.json | 8 +- .../errors__auth_missing_bearer_post.json | 8 +- .../errors__auth_oauth_issuer_off.json | 12 + .../canonical/errors__auth_oauth_only.json | 12 + ...rrors__auth_private_claim_ask_history.json | 8 +- .../errors__auth_private_claim_ask_send.json | 8 +- .../errors__auth_unrecognised_prefix.json | 8 +- ...rrors__http_error_library_bad_curated.json | 10 +- ...rrors__http_error_library_bad_verdict.json | 10 +- ...errors__method_not_allowed_get_verify.json | 12 + ...rors__method_not_allowed_post_library.json | 12 + .../canonical/errors__not_found_ask.json | 8 +- .../canonical/errors__not_found_route.json | 8 +- .../errors__not_found_verification.json | 8 +- .../errors__not_found_verify_status.json | 8 +- .../errors__oauth_register_disabled.json | 11 + ...auth_register_invalid_client_metadata.json | 12 + ...__oauth_register_invalid_redirect_uri.json | 12 + .../errors__oauth_revoke_invalid_client.json | 13 + .../errors__oauth_token_invalid_client.json | 13 + .../errors__oauth_token_invalid_grant.json | 12 + ...rrors__oauth_token_missing_grant_type.json | 11 + ...rs__oauth_token_refresh_invalid_grant.json | 12 + ...s__oauth_token_unsupported_grant_type.json | 11 + .../errors__payment_required_ask.json | 12 +- .../errors__payment_required_assess.json | 12 +- .../errors__payment_required_verify.json | 12 +- ...__payment_required_verify_batch_short.json | 12 +- .../errors__rate_limited_extract.json | 12 +- .../errors__service_unavailable_ask.json | 12 +- .../errors__service_unavailable_capacity.json | 12 +- .../errors__validation_malformed_json.json | 8 +- ...errors__validation_missing_field_hint.json | 10 +- ...errors__validation_unknown_field_only.json | 10 +- ...__validation_unknown_field_wrong_type.json | 10 +- .../errors__validation_wrong_type.json | 10 +- .../errors__web_assess_payment_required.json | 19 + .../errors__web_assess_signup_required.json | 14 + .../errors__web_review_rate_limited.json | 17 + .../parity/canonical/extract__401_no_key.json | 8 +- .../canonical/extract__422_blank_text.json | 10 +- .../extract__422_focus_too_long.json | 10 +- .../canonical/extract__422_missing_text.json | 10 +- .../canonical/extract__429_daily_limit.json | 12 +- .../extract__502_extraction_failed.json | 8 +- .../extract__503_upstream_unavailable.json | 12 +- .../canonical/extract__focus_ready.json | 10 +- ...xtract__idempotency_body_mismatch_422.json | 8 +- .../extract__idempotency_replay.json | 10 +- .../extract__locate_all_dropped.json | 10 +- .../canonical/extract__locate_failed.json | 10 +- .../extract__locate_leading_whitespace.json | 10 +- .../extract__locate_some_dropped.json | 10 +- .../canonical/extract__locate_true.json | 10 +- .../extract__no_match_with_focus.json | 10 +- .../canonical/extract__not_a_claim.json | 10 +- .../extract__not_a_claim_beside_claims.json | 10 +- .../canonical/extract__ready_one_claim.json | 10 +- .../extract__ready_several_claims.json | 10 +- .../canonical/extract__replay_later_200.json | 10 +- .../extract__url_fetch_502_unreadable.json | 8 +- .../extract__url_fetch_503_upstream.json | 12 +- .../canonical/extract__url_input_located.json | 10 +- .../canonical/review__401_no_credentials.json | 8 +- .../canonical/review__402_no_credits.json | 12 +- .../review__402_no_credits_exhausted.json | 12 +- .../canonical/review__422_blank_text.json | 10 +- .../review__422_citations_options_object.json | 10 +- .../canonical/review__422_depth_unknown.json | 10 +- .../review__422_invalid_confidence_band.json | 10 +- .../review__422_invalid_verdict_label.json | 10 +- .../review__422_max_assessments_negative.json | 10 +- .../review__422_max_citations_negative.json | 10 +- .../review__422_max_citations_too_big.json | 10 +- ...review__422_max_verifications_too_big.json | 10 +- .../canonical/review__422_text_missing.json | 10 +- .../review__422_text_wrong_type.json | 10 +- .../review__422_unknown_escalate_field.json | 10 +- .../review__422_unknown_top_level_field.json | 10 +- .../review__422_unsupported_language.json | 10 +- .../review__422_visibility_public.json | 10 +- .../review__422_webhook_secret_missing.json | 22 + .../review__429_extract_daily_limit.json | 12 +- .../review__429_review_in_flight.json | 10 +- .../canonical/review__503_capacity.json | 12 +- .../review__503_citations_capacity.json | 12 +- .../canonical/review__delete_not_a_route.json | 12 + .../review__get_403_insufficient_scope.json | 10 +- .../canonical/review__get_404_not_found.json | 8 +- .../review__get_404_other_account.json | 8 +- .../canonical/review__get_410_purged.json | 10 +- .../review__get_422_unknown_view.json | 10 +- .../canonical/review__get_assessing.json | 14 +- ...view__get_assessment_rows_full_fields.json | 14 +- .../review__get_citations_clean.json | 14 +- ...w__get_citations_failed_and_unchecked.json | 14 +- .../review__get_citations_issue_full.json | 14 +- ...view__get_citations_issue_issues_view.json | 14 +- ..._get_citations_limit_exactly_at_limit.json | 14 +- .../review__get_citations_limit_reached.json | 14 +- ..._get_citations_no_claim_but_citations.json | 14 +- ...w__get_citations_no_claim_no_citation.json | 14 +- .../review__get_citations_not_asked.json | 14 +- .../canonical/review__get_citations_only.json | 14 +- ...eview__get_citations_partly_supported.json | 14 +- .../review__get_citations_running.json | 12 +- ...w__get_citations_skipped_switched_off.json | 14 +- ...view__get_citations_skipped_url_input.json | 14 +- .../review__get_claim_limit_not_reached.json | 14 +- ...review__get_claim_limit_reached_exact.json | 14 +- .../review__get_completed_assess_only.json | 14 +- .../review__get_completed_clean.json | 14 +- ...ew__get_completed_issues_all_verified.json | 50 +- .../review__get_completed_issues_full.json | 34 +- ...iew__get_completed_issues_view_issues.json | 20 +- .../review__get_completed_positions.json | 14 +- ...review__get_completed_recovered_claim.json | 14 +- ...ew__get_completed_with_untraced_claim.json | 14 +- .../review__get_during_quick_check.json | 12 +- ...w__get_failed_every_assessment_failed.json | 14 +- .../review__get_failed_no_claim.json | 14 +- .../review__get_failed_no_claim_untraced.json | 14 +- .../canonical/review__get_more_claims.json | 14 +- ...dified_at_crosses_midnight_by_minutes.json | 28 +- ...tion_modified_at_same_day_hours_apart.json | 28 +- .../review__get_policy_resolved.json | 14 +- .../parity/canonical/review__get_queued.json | 12 +- .../review__get_suggested_edits.json | 30 +- ...view__get_suggested_edits_issues_view.json | 18 +- .../canonical/review__get_url_review.json | 14 +- .../canonical/review__get_verifying.json | 12 +- ...review__idempotency_body_mismatch_422.json | 8 +- .../review__idempotency_conflict_409.json | 10 +- ...mpotency_conflict_409_existing_review.json | 10 +- .../review__idempotent_replay_202.json | 8 +- .../parity/canonical/review__receipt_202.json | 8 +- ...review__receipt_202_empty_webhook_url.json | 8 +- .../review__receipt_202_webhook_url.json | 8 +- .../canonical/review__replay_later_202.json | 8 +- .../parity/canonical/verify__batch_202.json | 14 +- .../canonical/verify__batch_capacity_503.json | 12 +- .../canonical/verify__batch_empty_422.json | 10 +- ...erify__batch_idempotency_conflict_409.json | 10 +- .../verify__batch_item_missing_claim_422.json | 10 +- .../verify__batch_no_credits_402.json | 12 +- .../canonical/verify__batch_partial_202.json | 12 +- .../canonical/verify__batch_too_many_422.json | 10 +- .../canonical/verify__blank_claim_422.json | 10 +- .../canonical/verify__capacity_503.json | 12 +- .../parity/canonical/verify__delete_200.json | 11 + .../parity/canonical/verify__delete_404.json | 12 + .../verify__delete_not_yours_404.json | 12 + ...verify__idempotency_body_mismatch_422.json | 8 +- .../verify__idempotency_conflict_409.json | 10 +- .../verify__idempotency_key_replay.json | 8 +- .../canonical/verify__implicit_dedup_200.json | 8 +- .../verify__implicit_repeat_replay.json | 8 +- .../canonical/verify__invalid_depth_422.json | 10 +- .../verify__invalid_language_422.json | 10 +- .../parity/canonical/verify__list_200.json | 20 +- ...dified_at_crosses_midnight_by_minutes.json | 10 +- ..._200_modified_at_same_day_hours_apart.json | 10 +- .../canonical/verify__list_clamped_200.json | 10 +- .../canonical/verify__list_empty_200.json | 10 +- .../canonical/verify__list_page2_200.json | 14 +- .../canonical/verify__misnamed_field_422.json | 10 +- .../canonical/verify__missing_claim_422.json | 10 +- .../canonical/verify__no_credits_402.json | 12 +- .../canonical/verify__replay_later_202.json | 10 +- .../parity/canonical/verify__select_202.json | 14 +- .../canonical/verify__select_empty_422.json | 10 +- .../verify__select_invalid_selection_422.json | 10 +- ...rify__select_no_selection_pending_409.json | 8 +- .../verify__select_too_many_422.json | 10 +- .../verify__select_unknown_task_404.json | 8 +- ...erify__status_cancelled_after_a_while.json | 10 +- .../canonical/verify__status_completed.json | 16 +- ...erify__status_completed_after_a_while.json | 16 +- ...dified_at_crosses_midnight_by_minutes.json | 12 +- ...hile_modified_at_same_day_hours_apart.json | 12 +- ...dified_at_crosses_midnight_by_minutes.json | 12 +- ...eted_modified_at_same_day_hours_apart.json | 12 +- .../canonical/verify__status_failed.json | 10 +- .../verify__status_failed_after_a_while.json | 10 +- ...__status_failed_after_a_while_framing.json | 10 +- .../verify__status_failed_retryable.json | 10 +- .../canonical/verify__status_needs_input.json | 10 +- .../canonical/verify__status_not_a_claim.json | 10 +- ...ify__status_not_a_claim_after_a_while.json | 10 +- .../verify__status_not_yours_404.json | 8 +- .../verify__status_older_run_completed.json | 16 +- ...rify__status_older_run_failed_crashed.json | 10 +- ...lder_run_failed_insufficient_evidence.json | 10 +- .../verify__status_older_run_in_progress.json | 12 +- .../canonical/verify__status_processing.json | 12 +- ...rify__status_processing_after_a_while.json | 12 +- .../canonical/verify__status_task_stuck.json | 10 +- .../canonical/verify__status_unknown_404.json | 8 +- .../parity/canonical/verify__submit_202.json | 8 +- .../canonical/verify__submit_202_options.json | 8 +- .../verify__submit_202_text_alias.json | 8 +- .../verify__unauthenticated_401.json | 8 +- .../canonical/verify__verification_200.json | 14 +- .../verify__verification_200_covered.json | 18 +- ...dified_at_crosses_midnight_by_minutes.json | 10 +- ...fy__verification_200_modified_at_null.json | 14 +- ..._200_modified_at_same_day_hours_apart.json | 10 +- ...ify__verification_200_modified_at_set.json | 10 +- ...ation_200_result_json_conclusion_only.json | 14 +- ...y__verification_200_result_json_empty.json | 14 +- ...ion_200_result_json_old_shape_strings.json | 14 +- .../canonical/verify__verification_404.json | 8 +- .../verify__verification_by_task_id_200.json | 14 +- .../verify__verification_failed_409.json | 10 +- ..._failed_409_not_a_claim_after_a_while.json | 10 +- .../verify__verification_not_ready_409.json | 10 +- .../verify__verification_not_yours_404.json | 8 +- ...verify__verification_public_anonymous.json | 14 +- ...__verification_public_of_another_user.json | 14 +- ...verify__verification_unknown_task_404.json | 10 +- ...rification_zero_retention_expired_410.json | 10 +- ...y__verification_zero_retention_served.json | 14 +- .../verify__webhook_secret_missing_422.json | 22 + .../webhook__certificate_timestamped.json | 15 +- ..._certificate_timestamped_review_child.json | 17 +- .../webhook__citecheck_completed.json | 16 +- .../canonical/webhook__citecheck_failed.json | 21 +- .../canonical/webhook__review_completed.json | 43 +- ...ook__review_completed_key_default_url.json | 25 +- ...k__review_completed_oversized_rebuilt.json | 6 +- .../canonical/webhook__review_failed.json | 24 +- .../parity/canonical/webhook__test_fire.json | 12 + .../webhook__verification_completed.json | 19 +- ...hook__verification_completed_in_batch.json | 20 +- ...dified_at_crosses_midnight_by_minutes.json | 17 +- ...eted_modified_at_same_day_hours_apart.json | 17 +- ..._verification_completed_sparse_result.json | 22 + ...bhook__verification_failed_error_none.json | 24 + ...fication_failed_insufficient_evidence.json | 14 +- ...hook__verification_failed_not_a_claim.json | 16 +- ...ification_failed_upstream_unavailable.json | 14 +- ...k__verification_needs_input_hint_none.json | 24 + ..._verification_needs_input_multi_claim.json | 14 +- .../parity/expected/account__api_root.json | 1 + .../account__ask_history_after_reset.json | 1 + .../account__ask_history_after_send.json | 1 + .../expected/account__ask_history_empty.json | 1 + .../account__ask_history_messages.json | 1 + .../parity/expected/account__ask_reset.json | 1 + .../parity/expected/account__ask_send.json | 1 + .../expected/account__ask_send_language.json | 1 + .../expected/account__library_empty.json | 9 +- ...dified_at_crosses_midnight_by_minutes.json | 25 +- ...item_modified_at_same_day_hours_apart.json | 25 +- .../expected/account__library_items.json | 63 +- .../expected/account__library_no_match.json | 9 +- .../account__library_page_past_end.json | 9 +- ...ccount__library_paginated_second_page.json | 44 +- .../account__me_usage_extra_credits.json | 65 +- .../account__me_usage_extra_only.json | 65 +- .../account__me_usage_extract_calls.json | 65 +- .../expected/account__me_usage_free.json | 65 +- .../account__me_usage_free_partly_spent.json | 65 +- .../expected/account__me_usage_oauth.json | 121 + .../expected/account__me_usage_plus.json | 65 +- .../expected/account__me_usage_pro.json | 65 +- .../expected/account__me_usage_pro_extra.json | 65 +- .../account__me_usage_stale_quota_row.json | 65 +- .../account__oauth_register_success.json | 1 + .../expected/account__oauth_revoke.json | 1 + .../expected/account__oauth_revoke_token.json | 1 + .../account__webhook_secret_api_key.json | 21 + ...nt__webhook_secret_insufficient_scope.json | 21 + .../account__webhook_secret_oauth.json | 1 + .../expected/assess__402_no_credits.json | 2 +- .../expected/assess__deep_tier_hit.json | 23 +- .../expected/assess__idempotency_first.json | 23 +- .../expected/assess__idempotency_replay.json | 23 +- .../expected/assess__list_all_error_rows.json | 37 +- .../expected/assess__list_compound_item.json | 40 +- .../expected/assess__list_mixed_rows.json | 65 +- .../parity/expected/assess__memo_hit.json | 23 +- .../expected/assess__replay_later_200.json | 23 +- .../expected/assess__single_no_claim.json | 10 +- .../expected/assess__single_one_claim.json | 23 +- ...ss__single_text_over_wave_more_claims.json | 292 +- .../assess__single_text_several_claims.json | 51 +- .../expected/assess__suggest_rewrite.json | 37 +- .../expected/citecheck__402_no_credits.json | 2 +- ...citecheck__422_webhook_secret_missing.json | 30 + .../expected/citecheck__get_checking.json | 100 +- .../citecheck__get_completed_clean.json | 110 +- .../citecheck__get_completed_doi_pair.json | 75 +- .../citecheck__get_completed_incomplete.json | 126 +- ...citecheck__get_completed_issues_found.json | 140 +- ...check__get_completed_partly_supported.json | 110 +- .../citecheck__get_completed_unchecked.json | 110 +- .../citecheck__get_failed_no_citations.json | 41 +- ...heck__get_failed_upstream_unavailable.json | 147 +- .../expected/citecheck__get_queued.json | 69 +- ...heck__get_text_limit_exactly_at_limit.json | 118 +- .../citecheck__get_text_limit_reached.json | 92 +- .../citecheck__idempotent_replay_202.json | 7 +- .../expected/citecheck__receipt_202.json | 7 +- ...echeck__receipt_202_empty_webhook_url.json | 7 +- .../errors__auth_bad_oauth_token.json | 21 + .../errors__auth_expired_oauth_token.json | 21 + .../errors__auth_oauth_issuer_off.json | 21 + .../expected/errors__auth_oauth_only.json | 21 + ...errors__method_not_allowed_get_verify.json | 21 + ...rors__method_not_allowed_post_library.json | 21 + .../errors__oauth_register_disabled.json | 21 + ...auth_register_invalid_client_metadata.json | 21 + ...__oauth_register_invalid_redirect_uri.json | 21 + .../errors__oauth_revoke_invalid_client.json | 21 + .../errors__oauth_token_invalid_client.json | 21 + .../errors__oauth_token_invalid_grant.json | 21 + ...rrors__oauth_token_missing_grant_type.json | 21 + ...rs__oauth_token_refresh_invalid_grant.json | 21 + ...s__oauth_token_unsupported_grant_type.json | 21 + .../errors__payment_required_ask.json | 2 +- .../errors__payment_required_assess.json | 2 +- .../errors__payment_required_verify.json | 2 +- ...__payment_required_verify_batch_short.json | 2 +- .../errors__web_assess_payment_required.json | 28 + .../errors__web_assess_signup_required.json | 21 + .../errors__web_review_rate_limited.json | 25 + .../parity/expected/extract__focus_ready.json | 23 +- .../expected/extract__idempotency_replay.json | 26 +- .../expected/extract__locate_all_dropped.json | 23 +- .../expected/extract__locate_failed.json | 26 +- .../extract__locate_leading_whitespace.json | 34 +- .../extract__locate_some_dropped.json | 47 +- .../parity/expected/extract__locate_true.json | 47 +- .../extract__no_match_with_focus.json | 14 +- .../parity/expected/extract__not_a_claim.json | 14 +- .../extract__not_a_claim_beside_claims.json | 23 +- .../expected/extract__ready_one_claim.json | 23 +- .../extract__ready_several_claims.json | 26 +- .../expected/extract__replay_later_200.json | 26 +- .../expected/extract__url_input_located.json | 34 +- .../expected/review__402_no_credits.json | 2 +- .../review__402_no_credits_exhausted.json | 2 +- .../review__422_webhook_secret_missing.json | 30 + .../expected/review__delete_not_a_route.json | 21 + .../expected/review__get_assessing.json | 109 +- ...view__get_assessment_rows_full_fields.json | 169 +- .../expected/review__get_citations_clean.json | 182 +- ...w__get_citations_failed_and_unchecked.json | 198 +- .../review__get_citations_issue_full.json | 204 +- ...view__get_citations_issue_issues_view.json | 92 +- ..._get_citations_limit_exactly_at_limit.json | 182 +- .../review__get_citations_limit_reached.json | 156 +- ..._get_citations_no_claim_but_citations.json | 151 +- ...w__get_citations_no_claim_no_citation.json | 67 +- .../review__get_citations_not_asked.json | 99 +- .../expected/review__get_citations_only.json | 158 +- ...eview__get_citations_partly_supported.json | 182 +- .../review__get_citations_running.json | 164 +- ...w__get_citations_skipped_switched_off.json | 99 +- ...view__get_citations_skipped_url_input.json | 67 +- .../review__get_claim_limit_not_reached.json | 129 +- ...review__get_claim_limit_reached_exact.json | 129 +- .../review__get_completed_assess_only.json | 155 +- .../expected/review__get_completed_clean.json | 129 +- ...ew__get_completed_issues_all_verified.json | 296 +- .../review__get_completed_issues_full.json | 333 +- ...iew__get_completed_issues_view_issues.json | 140 +- .../review__get_completed_positions.json | 141 +- ...review__get_completed_recovered_claim.json | 99 +- ...ew__get_completed_with_untraced_claim.json | 141 +- .../review__get_during_quick_check.json | 85 +- ...w__get_failed_every_assessment_failed.json | 156 +- .../expected/review__get_failed_no_claim.json | 67 +- .../review__get_failed_no_claim_untraced.json | 67 +- .../expected/review__get_more_claims.json | 154 +- ...dified_at_crosses_midnight_by_minutes.json | 168 +- ...tion_modified_at_same_day_hours_apart.json | 168 +- .../expected/review__get_policy_resolved.json | 97 +- .../parity/expected/review__get_queued.json | 59 +- .../expected/review__get_suggested_edits.json | 286 +- ...view__get_suggested_edits_issues_view.json | 133 +- .../expected/review__get_url_review.json | 105 +- .../expected/review__get_verifying.json | 176 +- .../review__idempotent_replay_202.json | 7 +- .../parity/expected/review__receipt_202.json | 7 +- ...review__receipt_202_empty_webhook_url.json | 7 +- .../review__receipt_202_webhook_url.json | 7 +- .../expected/review__replay_later_202.json | 7 +- .../parity/expected/verify__batch_202.json | 18 +- .../verify__batch_no_credits_402.json | 2 +- .../expected/verify__batch_partial_202.json | 15 +- .../parity/expected/verify__delete_200.json | 12 + .../parity/expected/verify__delete_404.json | 21 + .../verify__delete_not_yours_404.json | 21 + .../verify__idempotency_key_replay.json | 10 +- .../expected/verify__implicit_dedup_200.json | 7 +- .../verify__implicit_repeat_replay.json | 10 +- .../parity/expected/verify__list_200.json | 44 +- ...dified_at_crosses_midnight_by_minutes.json | 25 +- ..._200_modified_at_same_day_hours_apart.json | 25 +- .../expected/verify__list_clamped_200.json | 9 +- .../expected/verify__list_empty_200.json | 9 +- .../expected/verify__list_page2_200.json | 27 +- .../expected/verify__no_credits_402.json | 2 +- .../expected/verify__replay_later_202.json | 10 +- .../parity/expected/verify__select_202.json | 18 +- ...erify__status_cancelled_after_a_while.json | 10 + .../expected/verify__status_completed.json | 106 +- ...erify__status_completed_after_a_while.json | 106 +- ...dified_at_crosses_midnight_by_minutes.json | 102 +- ...hile_modified_at_same_day_hours_apart.json | 102 +- ...dified_at_crosses_midnight_by_minutes.json | 102 +- ...eted_modified_at_same_day_hours_apart.json | 102 +- .../expected/verify__status_failed.json | 10 + .../verify__status_failed_after_a_while.json | 10 + ...__status_failed_after_a_while_framing.json | 10 + .../verify__status_failed_retryable.json | 10 + .../expected/verify__status_needs_input.json | 17 + .../expected/verify__status_not_a_claim.json | 11 + ...ify__status_not_a_claim_after_a_while.json | 10 + .../verify__status_older_run_completed.json | 106 +- ...rify__status_older_run_failed_crashed.json | 10 + ...lder_run_failed_insufficient_evidence.json | 10 + .../verify__status_older_run_in_progress.json | 16 +- .../expected/verify__status_processing.json | 16 +- ...rify__status_processing_after_a_while.json | 16 +- .../expected/verify__status_task_stuck.json | 10 + .../parity/expected/verify__submit_202.json | 10 +- .../expected/verify__submit_202_options.json | 10 +- .../verify__submit_202_text_alias.json | 10 +- .../expected/verify__verification_200.json | 92 +- .../verify__verification_200_covered.json | 94 +- ...dified_at_crosses_midnight_by_minutes.json | 90 +- ...fy__verification_200_modified_at_null.json | 92 +- ..._200_modified_at_same_day_hours_apart.json | 90 +- ...ify__verification_200_modified_at_set.json | 90 +- ...ation_200_result_json_conclusion_only.json | 53 +- ...y__verification_200_result_json_empty.json | 53 +- ...ion_200_result_json_old_shape_strings.json | 69 +- .../verify__verification_by_task_id_200.json | 92 +- ...verify__verification_public_anonymous.json | 80 +- ...__verification_public_of_another_user.json | 92 +- ...y__verification_zero_retention_served.json | 92 +- .../verify__webhook_secret_missing_422.json | 22 + .../webhook__certificate_timestamped.json | 8 +- ..._certificate_timestamped_review_child.json | 8 +- .../webhook__citecheck_completed.json | 12 +- .../expected/webhook__citecheck_failed.json | 12 +- .../expected/webhook__review_completed.json | 28 +- ...ook__review_completed_key_default_url.json | 12 +- ...k__review_completed_oversized_rebuilt.json | 4 +- .../expected/webhook__review_failed.json | 12 +- .../parity/expected/webhook__test_fire.json | 12 + .../webhook__verification_completed.json | 6 +- ...hook__verification_completed_in_batch.json | 8 +- ...dified_at_crosses_midnight_by_minutes.json | 4 +- ...eted_modified_at_same_day_hours_apart.json | 4 +- ..._verification_completed_sparse_result.json | 48 + ...bhook__verification_failed_error_none.json | 15 + ...fication_failed_insufficient_evidence.json | 2 +- ...hook__verification_failed_not_a_claim.json | 2 +- ...ification_failed_upstream_unavailable.json | 2 +- ...k__verification_needs_input_hint_none.json | 23 + ..._verification_needs_input_multi_claim.json | 2 +- .../parity/legacy/account__api_root.json | 43 + .../account__ask_history_after_reset.json | 14 + .../account__ask_history_after_send.json | 25 + .../legacy/account__ask_history_empty.json | 14 + .../legacy/account__ask_history_messages.json | 25 + .../parity/legacy/account__ask_reset.json | 11 + .../parity/legacy/account__ask_send.json | 13 + .../legacy/account__ask_send_language.json | 13 + .../parity/legacy/account__library_empty.json | 10 +- ...dified_at_crosses_midnight_by_minutes.json | 10 +- ...item_modified_at_same_day_hours_apart.json | 10 +- .../parity/legacy/account__library_items.json | 20 +- .../legacy/account__library_no_match.json | 10 +- .../account__library_page_past_end.json | 10 +- ...ccount__library_paginated_second_page.json | 16 +- .../account__me_usage_extra_credits.json | 14 +- .../legacy/account__me_usage_extra_only.json | 14 +- .../account__me_usage_extract_calls.json | 14 +- .../parity/legacy/account__me_usage_free.json | 14 +- .../account__me_usage_free_partly_spent.json | 14 +- .../legacy/account__me_usage_oauth.json | 66 + .../parity/legacy/account__me_usage_plus.json | 14 +- .../parity/legacy/account__me_usage_pro.json | 14 +- .../legacy/account__me_usage_pro_extra.json | 14 +- .../account__me_usage_stale_quota_row.json | 14 +- .../account__oauth_register_success.json | 25 + .../parity/legacy/account__oauth_revoke.json | 9 + .../legacy/account__oauth_revoke_token.json | 9 + .../account__webhook_secret_api_key.json | 12 + ...nt__webhook_secret_insufficient_scope.json | 14 + .../legacy/account__webhook_secret_oauth.json | 11 + .../parity/legacy/assess__401_no_key.json | 6 +- .../parity/legacy/assess__402_no_credits.json | 12 +- .../parity/legacy/assess__422_blank_item.json | 8 +- .../parity/legacy/assess__422_blank_text.json | 6 +- .../legacy/assess__422_input_conflict.json | 8 +- .../legacy/assess__422_item_too_long.json | 8 +- .../legacy/assess__422_no_input_field.json | 10 +- .../legacy/assess__422_too_many_items.json | 8 +- .../legacy/assess__422_wrong_type_claim.json | 10 +- .../legacy/assess__422_wrong_type_claims.json | 10 +- .../legacy/assess__502_framing_failed.json | 10 +- .../parity/legacy/assess__503_capacity.json | 12 +- ...ss__503_list_all_upstream_unavailable.json | 12 +- .../assess__503_upstream_unavailable.json | 12 +- .../parity/legacy/assess__deep_tier_hit.json | 10 +- .../assess__idempotency_body_mismatch.json | 6 +- .../legacy/assess__idempotency_first.json | 10 +- .../legacy/assess__idempotency_replay.json | 10 +- .../legacy/assess__list_all_error_rows.json | 10 +- .../legacy/assess__list_compound_item.json | 10 +- .../legacy/assess__list_mixed_rows.json | 10 +- .../parity/legacy/assess__memo_hit.json | 10 +- .../legacy/assess__replay_later_200.json | 10 +- .../legacy/assess__single_no_claim.json | 10 +- .../legacy/assess__single_one_claim.json | 10 +- ...ss__single_text_over_wave_more_claims.json | 10 +- .../assess__single_text_several_claims.json | 10 +- .../legacy/assess__suggest_rewrite.json | 10 +- .../legacy/citecheck__402_no_credits.json | 12 +- .../legacy/citecheck__422_empty_body.json | 10 +- .../legacy/citecheck__422_invalid_doi.json | 10 +- .../citecheck__422_max_citations_over_20.json | 10 +- ...techeck__422_max_citations_with_pairs.json | 10 +- .../citecheck__422_pair_bad_url_scheme.json | 10 +- .../legacy/citecheck__422_pair_no_source.json | 10 +- .../citecheck__422_pair_url_and_doi.json | 10 +- .../legacy/citecheck__422_pairs_empty.json | 10 +- .../legacy/citecheck__422_pairs_over_20.json | 10 +- ...citecheck__422_quote_not_in_statement.json | 10 +- .../legacy/citecheck__422_text_and_pairs.json | 10 +- .../legacy/citecheck__422_unknown_field.json | 10 +- .../legacy/citecheck__422_url_input.json | 10 +- ...citecheck__422_webhook_secret_missing.json | 21 + .../citecheck__429_citecheck_in_flight.json | 10 +- .../legacy/citecheck__503_capacity.json | 12 +- .../citecheck__503_citations_unavailable.json | 12 +- .../legacy/citecheck__get_404_not_found.json | 8 +- .../legacy/citecheck__get_404_review_id.json | 8 +- .../legacy/citecheck__get_410_purged.json | 10 +- .../legacy/citecheck__get_checking.json | 12 +- .../citecheck__get_completed_clean.json | 14 +- .../citecheck__get_completed_doi_pair.json | 14 +- .../citecheck__get_completed_incomplete.json | 14 +- ...citecheck__get_completed_issues_found.json | 14 +- ...check__get_completed_partly_supported.json | 14 +- .../citecheck__get_completed_unchecked.json | 14 +- .../citecheck__get_failed_no_citations.json | 14 +- ...heck__get_failed_upstream_unavailable.json | 14 +- .../parity/legacy/citecheck__get_queued.json | 12 +- ...heck__get_text_limit_exactly_at_limit.json | 14 +- .../citecheck__get_text_limit_reached.json | 14 +- ...echeck__idempotency_body_mismatch_422.json | 10 +- .../citecheck__idempotency_conflict_409.json | 10 +- .../citecheck__idempotent_replay_202.json | 8 +- .../parity/legacy/citecheck__receipt_202.json | 8 +- ...echeck__receipt_202_empty_webhook_url.json | 8 +- .../legacy/errors__ask_bad_language.json | 6 +- .../legacy/errors__ask_empty_message.json | 6 +- .../parity/legacy/errors__ask_failed.json | 10 +- .../errors__ask_idempotency_key_reused.json | 6 +- .../legacy/errors__ask_message_too_long.json | 6 +- .../legacy/errors__ask_not_completed.json | 6 +- .../legacy/errors__ask_reset_not_found.json | 6 +- .../legacy/errors__ask_send_not_found.json | 6 +- .../parity/legacy/errors__auth_bad_key.json | 6 +- .../legacy/errors__auth_bad_oauth_token.json | 13 + .../legacy/errors__auth_basic_scheme.json | 6 +- .../errors__auth_expired_oauth_token.json | 13 + .../errors__auth_insufficient_scope.json | 10 +- .../legacy/errors__auth_missing_bearer.json | 6 +- .../errors__auth_missing_bearer_post.json | 6 +- .../legacy/errors__auth_oauth_issuer_off.json | 11 + .../legacy/errors__auth_oauth_only.json | 12 + ...rrors__auth_private_claim_ask_history.json | 10 +- .../errors__auth_private_claim_ask_send.json | 10 +- .../errors__auth_unrecognised_prefix.json | 6 +- ...rrors__http_error_library_bad_curated.json | 6 +- ...rrors__http_error_library_bad_verdict.json | 6 +- ...errors__method_not_allowed_get_verify.json | 11 + ...rors__method_not_allowed_post_library.json | 11 + .../parity/legacy/errors__not_found_ask.json | 6 +- .../legacy/errors__not_found_route.json | 6 +- .../errors__not_found_verification.json | 6 +- .../errors__not_found_verify_status.json | 6 +- .../errors__oauth_register_disabled.json | 11 + ...auth_register_invalid_client_metadata.json | 12 + ...__oauth_register_invalid_redirect_uri.json | 12 + .../errors__oauth_revoke_invalid_client.json | 13 + .../errors__oauth_token_invalid_client.json | 13 + .../errors__oauth_token_invalid_grant.json | 12 + ...rrors__oauth_token_missing_grant_type.json | 11 + ...rs__oauth_token_refresh_invalid_grant.json | 12 + ...s__oauth_token_unsupported_grant_type.json | 11 + .../legacy/errors__payment_required_ask.json | 12 +- .../errors__payment_required_assess.json | 12 +- .../errors__payment_required_verify.json | 12 +- ...__payment_required_verify_batch_short.json | 12 +- .../legacy/errors__rate_limited_extract.json | 12 +- .../errors__service_unavailable_ask.json | 12 +- .../errors__service_unavailable_capacity.json | 12 +- .../errors__validation_malformed_json.json | 6 +- ...errors__validation_missing_field_hint.json | 10 +- ...errors__validation_unknown_field_only.json | 10 +- ...__validation_unknown_field_wrong_type.json | 10 +- .../legacy/errors__validation_wrong_type.json | 10 +- .../errors__web_assess_payment_required.json | 19 + .../errors__web_assess_signup_required.json | 14 + .../errors__web_review_rate_limited.json | 17 + .../parity/legacy/extract__401_no_key.json | 6 +- .../legacy/extract__422_blank_text.json | 6 +- .../legacy/extract__422_focus_too_long.json | 6 +- .../legacy/extract__422_missing_text.json | 10 +- .../legacy/extract__429_daily_limit.json | 12 +- .../extract__502_extraction_failed.json | 10 +- .../extract__503_upstream_unavailable.json | 12 +- .../parity/legacy/extract__focus_ready.json | 10 +- ...xtract__idempotency_body_mismatch_422.json | 6 +- .../legacy/extract__idempotency_replay.json | 10 +- .../legacy/extract__locate_all_dropped.json | 10 +- .../parity/legacy/extract__locate_failed.json | 10 +- .../extract__locate_leading_whitespace.json | 10 +- .../legacy/extract__locate_some_dropped.json | 10 +- .../parity/legacy/extract__locate_true.json | 10 +- .../legacy/extract__no_match_with_focus.json | 10 +- .../parity/legacy/extract__not_a_claim.json | 10 +- .../extract__not_a_claim_beside_claims.json | 10 +- .../legacy/extract__ready_one_claim.json | 10 +- .../legacy/extract__ready_several_claims.json | 10 +- .../legacy/extract__replay_later_200.json | 10 +- .../extract__url_fetch_502_unreadable.json | 10 +- .../extract__url_fetch_503_upstream.json | 12 +- .../legacy/extract__url_input_located.json | 10 +- .../legacy/review__401_no_credentials.json | 6 +- .../parity/legacy/review__402_no_credits.json | 12 +- .../review__402_no_credits_exhausted.json | 12 +- .../parity/legacy/review__422_blank_text.json | 10 +- .../review__422_citations_options_object.json | 10 +- .../legacy/review__422_depth_unknown.json | 10 +- .../review__422_invalid_confidence_band.json | 10 +- .../review__422_invalid_verdict_label.json | 10 +- .../review__422_max_assessments_negative.json | 10 +- .../review__422_max_citations_negative.json | 10 +- .../review__422_max_citations_too_big.json | 10 +- ...review__422_max_verifications_too_big.json | 10 +- .../legacy/review__422_text_missing.json | 10 +- .../legacy/review__422_text_wrong_type.json | 10 +- .../review__422_unknown_escalate_field.json | 10 +- .../review__422_unknown_top_level_field.json | 10 +- .../review__422_unsupported_language.json | 10 +- .../legacy/review__422_visibility_public.json | 10 +- .../review__422_webhook_secret_missing.json | 21 + .../review__429_extract_daily_limit.json | 12 +- .../legacy/review__429_review_in_flight.json | 10 +- .../parity/legacy/review__503_capacity.json | 12 +- .../review__503_citations_capacity.json | 12 +- .../legacy/review__delete_not_a_route.json | 11 + .../review__get_403_insufficient_scope.json | 10 +- .../legacy/review__get_404_not_found.json | 8 +- .../legacy/review__get_404_other_account.json | 8 +- .../parity/legacy/review__get_410_purged.json | 10 +- .../legacy/review__get_422_unknown_view.json | 10 +- .../parity/legacy/review__get_assessing.json | 14 +- ...view__get_assessment_rows_full_fields.json | 14 +- .../legacy/review__get_citations_clean.json | 14 +- ...w__get_citations_failed_and_unchecked.json | 14 +- .../review__get_citations_issue_full.json | 14 +- ...view__get_citations_issue_issues_view.json | 14 +- ..._get_citations_limit_exactly_at_limit.json | 14 +- .../review__get_citations_limit_reached.json | 14 +- ..._get_citations_no_claim_but_citations.json | 14 +- ...w__get_citations_no_claim_no_citation.json | 14 +- .../review__get_citations_not_asked.json | 14 +- .../legacy/review__get_citations_only.json | 14 +- ...eview__get_citations_partly_supported.json | 14 +- .../legacy/review__get_citations_running.json | 12 +- ...w__get_citations_skipped_switched_off.json | 14 +- ...view__get_citations_skipped_url_input.json | 14 +- .../review__get_claim_limit_not_reached.json | 14 +- ...review__get_claim_limit_reached_exact.json | 14 +- .../review__get_completed_assess_only.json | 14 +- .../legacy/review__get_completed_clean.json | 14 +- ...ew__get_completed_issues_all_verified.json | 46 +- .../review__get_completed_issues_full.json | 32 +- ...iew__get_completed_issues_view_issues.json | 20 +- .../review__get_completed_positions.json | 14 +- ...review__get_completed_recovered_claim.json | 14 +- ...ew__get_completed_with_untraced_claim.json | 14 +- .../review__get_during_quick_check.json | 12 +- ...w__get_failed_every_assessment_failed.json | 14 +- .../legacy/review__get_failed_no_claim.json | 14 +- .../review__get_failed_no_claim_untraced.json | 14 +- .../legacy/review__get_more_claims.json | 14 +- ...dified_at_crosses_midnight_by_minutes.json | 28 +- ...tion_modified_at_same_day_hours_apart.json | 28 +- .../legacy/review__get_policy_resolved.json | 14 +- .../parity/legacy/review__get_queued.json | 12 +- .../legacy/review__get_suggested_edits.json | 28 +- ...view__get_suggested_edits_issues_view.json | 18 +- .../parity/legacy/review__get_url_review.json | 14 +- .../parity/legacy/review__get_verifying.json | 12 +- ...review__idempotency_body_mismatch_422.json | 10 +- .../review__idempotency_conflict_409.json | 10 +- ...mpotency_conflict_409_existing_review.json | 10 +- .../legacy/review__idempotent_replay_202.json | 8 +- .../parity/legacy/review__receipt_202.json | 8 +- ...review__receipt_202_empty_webhook_url.json | 8 +- .../review__receipt_202_webhook_url.json | 8 +- .../legacy/review__replay_later_202.json | 8 +- .../parity/legacy/verify__batch_202.json | 14 +- .../legacy/verify__batch_capacity_503.json | 12 +- .../legacy/verify__batch_empty_422.json | 6 +- ...erify__batch_idempotency_conflict_409.json | 8 +- .../verify__batch_item_missing_claim_422.json | 10 +- .../legacy/verify__batch_no_credits_402.json | 12 +- .../legacy/verify__batch_partial_202.json | 12 +- .../legacy/verify__batch_too_many_422.json | 6 +- .../legacy/verify__blank_claim_422.json | 6 +- .../parity/legacy/verify__capacity_503.json | 12 +- .../parity/legacy/verify__delete_200.json | 11 + .../parity/legacy/verify__delete_404.json | 11 + .../legacy/verify__delete_not_yours_404.json | 11 + ...verify__idempotency_body_mismatch_422.json | 6 +- .../verify__idempotency_conflict_409.json | 8 +- .../verify__idempotency_key_replay.json | 10 +- .../legacy/verify__implicit_dedup_200.json | 8 +- .../verify__implicit_repeat_replay.json | 10 +- .../legacy/verify__invalid_depth_422.json | 10 +- .../legacy/verify__invalid_language_422.json | 6 +- .../parity/legacy/verify__list_200.json | 16 +- ...dified_at_crosses_midnight_by_minutes.json | 10 +- ..._200_modified_at_same_day_hours_apart.json | 10 +- .../legacy/verify__list_clamped_200.json | 10 +- .../parity/legacy/verify__list_empty_200.json | 10 +- .../parity/legacy/verify__list_page2_200.json | 12 +- .../legacy/verify__misnamed_field_422.json | 10 +- .../legacy/verify__missing_claim_422.json | 10 +- .../parity/legacy/verify__no_credits_402.json | 12 +- .../legacy/verify__replay_later_202.json | 10 +- .../parity/legacy/verify__select_202.json | 14 +- .../legacy/verify__select_empty_422.json | 6 +- .../verify__select_invalid_selection_422.json | 10 +- ...rify__select_no_selection_pending_409.json | 10 +- .../legacy/verify__select_too_many_422.json | 6 +- .../verify__select_unknown_task_404.json | 6 +- ...erify__status_cancelled_after_a_while.json | 10 +- .../legacy/verify__status_completed.json | 14 +- ...erify__status_completed_after_a_while.json | 14 +- ...dified_at_crosses_midnight_by_minutes.json | 12 +- ...hile_modified_at_same_day_hours_apart.json | 12 +- ...dified_at_crosses_midnight_by_minutes.json | 12 +- ...eted_modified_at_same_day_hours_apart.json | 12 +- .../parity/legacy/verify__status_failed.json | 10 +- .../verify__status_failed_after_a_while.json | 10 +- ...__status_failed_after_a_while_framing.json | 10 +- .../verify__status_failed_retryable.json | 10 +- .../legacy/verify__status_needs_input.json | 10 +- .../legacy/verify__status_not_a_claim.json | 10 +- ...ify__status_not_a_claim_after_a_while.json | 10 +- .../legacy/verify__status_not_yours_404.json | 6 +- .../verify__status_older_run_completed.json | 14 +- ...rify__status_older_run_failed_crashed.json | 10 +- ...lder_run_failed_insufficient_evidence.json | 10 +- .../verify__status_older_run_in_progress.json | 12 +- .../legacy/verify__status_processing.json | 12 +- ...rify__status_processing_after_a_while.json | 12 +- .../legacy/verify__status_task_stuck.json | 10 +- .../legacy/verify__status_unknown_404.json | 6 +- .../parity/legacy/verify__submit_202.json | 10 +- .../legacy/verify__submit_202_options.json | 10 +- .../legacy/verify__submit_202_text_alias.json | 10 +- .../legacy/verify__unauthenticated_401.json | 6 +- .../legacy/verify__verification_200.json | 12 +- .../verify__verification_200_covered.json | 16 +- ...dified_at_crosses_midnight_by_minutes.json | 10 +- ...fy__verification_200_modified_at_null.json | 12 +- ..._200_modified_at_same_day_hours_apart.json | 10 +- ...ify__verification_200_modified_at_set.json | 10 +- ...ation_200_result_json_conclusion_only.json | 12 +- ...y__verification_200_result_json_empty.json | 12 +- ...ion_200_result_json_old_shape_strings.json | 12 +- .../legacy/verify__verification_404.json | 6 +- .../verify__verification_by_task_id_200.json | 12 +- .../verify__verification_failed_409.json | 10 +- ..._failed_409_not_a_claim_after_a_while.json | 10 +- .../verify__verification_not_ready_409.json | 10 +- .../verify__verification_not_yours_404.json | 6 +- ...verify__verification_public_anonymous.json | 12 +- ...__verification_public_of_another_user.json | 12 +- ...verify__verification_unknown_task_404.json | 8 +- ...rification_zero_retention_expired_410.json | 10 +- ...y__verification_zero_retention_served.json | 12 +- .../verify__webhook_secret_missing_422.json | 12 + .../webhook__certificate_timestamped.json | 12 +- ..._certificate_timestamped_review_child.json | 12 +- .../legacy/webhook__citecheck_completed.json | 16 +- .../legacy/webhook__citecheck_failed.json | 16 +- .../legacy/webhook__review_completed.json | 32 +- ...ook__review_completed_key_default_url.json | 16 +- ...k__review_completed_oversized_rebuilt.json | 8 +- .../parity/legacy/webhook__review_failed.json | 16 +- .../parity/legacy/webhook__test_fire.json | 17 + .../webhook__verification_completed.json | 10 +- ...hook__verification_completed_in_batch.json | 12 +- ...dified_at_crosses_midnight_by_minutes.json | 8 +- ...eted_modified_at_same_day_hours_apart.json | 8 +- ..._verification_completed_sparse_result.json | 52 + ...bhook__verification_failed_error_none.json | 19 + ...fication_failed_insufficient_evidence.json | 6 +- ...hook__verification_failed_not_a_claim.json | 6 +- ...ification_failed_upstream_unavailable.json | 6 +- ...k__verification_needs_input_hint_none.json | 27 + ..._verification_needs_input_multi_claim.json | 6 +- tests/fixtures/parity/pickles.json | 156 + tests/fixtures/parity/schemas.json | 26564 ++++++++++++++++ tests/parity_generate.py | 8 + tests/parity_observe.py | 28 +- tests/parity_static.py | 46 + tests/test_parity.py | 79 +- tests/test_read_both_shapes.py | 77 +- 944 files changed, 44136 insertions(+), 4731 deletions(-) create mode 100644 tests/fixtures/parity/canonical/account__api_root.json create mode 100644 tests/fixtures/parity/canonical/account__ask_history_after_reset.json create mode 100644 tests/fixtures/parity/canonical/account__ask_history_after_send.json create mode 100644 tests/fixtures/parity/canonical/account__ask_history_empty.json create mode 100644 tests/fixtures/parity/canonical/account__ask_history_messages.json create mode 100644 tests/fixtures/parity/canonical/account__ask_reset.json create mode 100644 tests/fixtures/parity/canonical/account__ask_send.json create mode 100644 tests/fixtures/parity/canonical/account__ask_send_language.json create mode 100644 tests/fixtures/parity/canonical/account__me_usage_oauth.json create mode 100644 tests/fixtures/parity/canonical/account__oauth_register_success.json create mode 100644 tests/fixtures/parity/canonical/account__oauth_revoke.json create mode 100644 tests/fixtures/parity/canonical/account__oauth_revoke_token.json create mode 100644 tests/fixtures/parity/canonical/account__webhook_secret_api_key.json create mode 100644 tests/fixtures/parity/canonical/account__webhook_secret_insufficient_scope.json create mode 100644 tests/fixtures/parity/canonical/account__webhook_secret_oauth.json create mode 100644 tests/fixtures/parity/canonical/citecheck__422_webhook_secret_missing.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_bad_oauth_token.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_expired_oauth_token.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_oauth_issuer_off.json create mode 100644 tests/fixtures/parity/canonical/errors__auth_oauth_only.json create mode 100644 tests/fixtures/parity/canonical/errors__method_not_allowed_get_verify.json create mode 100644 tests/fixtures/parity/canonical/errors__method_not_allowed_post_library.json create mode 100644 tests/fixtures/parity/canonical/errors__oauth_register_disabled.json create mode 100644 tests/fixtures/parity/canonical/errors__oauth_register_invalid_client_metadata.json create mode 100644 tests/fixtures/parity/canonical/errors__oauth_register_invalid_redirect_uri.json create mode 100644 tests/fixtures/parity/canonical/errors__oauth_revoke_invalid_client.json create mode 100644 tests/fixtures/parity/canonical/errors__oauth_token_invalid_client.json create mode 100644 tests/fixtures/parity/canonical/errors__oauth_token_invalid_grant.json create mode 100644 tests/fixtures/parity/canonical/errors__oauth_token_missing_grant_type.json create mode 100644 tests/fixtures/parity/canonical/errors__oauth_token_refresh_invalid_grant.json create mode 100644 tests/fixtures/parity/canonical/errors__oauth_token_unsupported_grant_type.json create mode 100644 tests/fixtures/parity/canonical/errors__web_assess_payment_required.json create mode 100644 tests/fixtures/parity/canonical/errors__web_assess_signup_required.json create mode 100644 tests/fixtures/parity/canonical/errors__web_review_rate_limited.json create mode 100644 tests/fixtures/parity/canonical/review__422_webhook_secret_missing.json create mode 100644 tests/fixtures/parity/canonical/review__delete_not_a_route.json create mode 100644 tests/fixtures/parity/canonical/verify__delete_200.json create mode 100644 tests/fixtures/parity/canonical/verify__delete_404.json create mode 100644 tests/fixtures/parity/canonical/verify__delete_not_yours_404.json create mode 100644 tests/fixtures/parity/canonical/verify__webhook_secret_missing_422.json create mode 100644 tests/fixtures/parity/canonical/webhook__test_fire.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_completed_sparse_result.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_failed_error_none.json create mode 100644 tests/fixtures/parity/canonical/webhook__verification_needs_input_hint_none.json create mode 100644 tests/fixtures/parity/expected/account__api_root.json create mode 100644 tests/fixtures/parity/expected/account__ask_history_after_reset.json create mode 100644 tests/fixtures/parity/expected/account__ask_history_after_send.json create mode 100644 tests/fixtures/parity/expected/account__ask_history_empty.json create mode 100644 tests/fixtures/parity/expected/account__ask_history_messages.json create mode 100644 tests/fixtures/parity/expected/account__ask_reset.json create mode 100644 tests/fixtures/parity/expected/account__ask_send.json create mode 100644 tests/fixtures/parity/expected/account__ask_send_language.json create mode 100644 tests/fixtures/parity/expected/account__me_usage_oauth.json create mode 100644 tests/fixtures/parity/expected/account__oauth_register_success.json create mode 100644 tests/fixtures/parity/expected/account__oauth_revoke.json create mode 100644 tests/fixtures/parity/expected/account__oauth_revoke_token.json create mode 100644 tests/fixtures/parity/expected/account__webhook_secret_api_key.json create mode 100644 tests/fixtures/parity/expected/account__webhook_secret_insufficient_scope.json create mode 100644 tests/fixtures/parity/expected/account__webhook_secret_oauth.json create mode 100644 tests/fixtures/parity/expected/citecheck__422_webhook_secret_missing.json create mode 100644 tests/fixtures/parity/expected/errors__auth_bad_oauth_token.json create mode 100644 tests/fixtures/parity/expected/errors__auth_expired_oauth_token.json create mode 100644 tests/fixtures/parity/expected/errors__auth_oauth_issuer_off.json create mode 100644 tests/fixtures/parity/expected/errors__auth_oauth_only.json create mode 100644 tests/fixtures/parity/expected/errors__method_not_allowed_get_verify.json create mode 100644 tests/fixtures/parity/expected/errors__method_not_allowed_post_library.json create mode 100644 tests/fixtures/parity/expected/errors__oauth_register_disabled.json create mode 100644 tests/fixtures/parity/expected/errors__oauth_register_invalid_client_metadata.json create mode 100644 tests/fixtures/parity/expected/errors__oauth_register_invalid_redirect_uri.json create mode 100644 tests/fixtures/parity/expected/errors__oauth_revoke_invalid_client.json create mode 100644 tests/fixtures/parity/expected/errors__oauth_token_invalid_client.json create mode 100644 tests/fixtures/parity/expected/errors__oauth_token_invalid_grant.json create mode 100644 tests/fixtures/parity/expected/errors__oauth_token_missing_grant_type.json create mode 100644 tests/fixtures/parity/expected/errors__oauth_token_refresh_invalid_grant.json create mode 100644 tests/fixtures/parity/expected/errors__oauth_token_unsupported_grant_type.json create mode 100644 tests/fixtures/parity/expected/errors__web_assess_payment_required.json create mode 100644 tests/fixtures/parity/expected/errors__web_assess_signup_required.json create mode 100644 tests/fixtures/parity/expected/errors__web_review_rate_limited.json create mode 100644 tests/fixtures/parity/expected/review__422_webhook_secret_missing.json create mode 100644 tests/fixtures/parity/expected/review__delete_not_a_route.json create mode 100644 tests/fixtures/parity/expected/verify__delete_200.json create mode 100644 tests/fixtures/parity/expected/verify__delete_404.json create mode 100644 tests/fixtures/parity/expected/verify__delete_not_yours_404.json create mode 100644 tests/fixtures/parity/expected/verify__webhook_secret_missing_422.json create mode 100644 tests/fixtures/parity/expected/webhook__test_fire.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_completed_sparse_result.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_failed_error_none.json create mode 100644 tests/fixtures/parity/expected/webhook__verification_needs_input_hint_none.json create mode 100644 tests/fixtures/parity/legacy/account__api_root.json create mode 100644 tests/fixtures/parity/legacy/account__ask_history_after_reset.json create mode 100644 tests/fixtures/parity/legacy/account__ask_history_after_send.json create mode 100644 tests/fixtures/parity/legacy/account__ask_history_empty.json create mode 100644 tests/fixtures/parity/legacy/account__ask_history_messages.json create mode 100644 tests/fixtures/parity/legacy/account__ask_reset.json create mode 100644 tests/fixtures/parity/legacy/account__ask_send.json create mode 100644 tests/fixtures/parity/legacy/account__ask_send_language.json create mode 100644 tests/fixtures/parity/legacy/account__me_usage_oauth.json create mode 100644 tests/fixtures/parity/legacy/account__oauth_register_success.json create mode 100644 tests/fixtures/parity/legacy/account__oauth_revoke.json create mode 100644 tests/fixtures/parity/legacy/account__oauth_revoke_token.json create mode 100644 tests/fixtures/parity/legacy/account__webhook_secret_api_key.json create mode 100644 tests/fixtures/parity/legacy/account__webhook_secret_insufficient_scope.json create mode 100644 tests/fixtures/parity/legacy/account__webhook_secret_oauth.json create mode 100644 tests/fixtures/parity/legacy/citecheck__422_webhook_secret_missing.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_bad_oauth_token.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_expired_oauth_token.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_oauth_issuer_off.json create mode 100644 tests/fixtures/parity/legacy/errors__auth_oauth_only.json create mode 100644 tests/fixtures/parity/legacy/errors__method_not_allowed_get_verify.json create mode 100644 tests/fixtures/parity/legacy/errors__method_not_allowed_post_library.json create mode 100644 tests/fixtures/parity/legacy/errors__oauth_register_disabled.json create mode 100644 tests/fixtures/parity/legacy/errors__oauth_register_invalid_client_metadata.json create mode 100644 tests/fixtures/parity/legacy/errors__oauth_register_invalid_redirect_uri.json create mode 100644 tests/fixtures/parity/legacy/errors__oauth_revoke_invalid_client.json create mode 100644 tests/fixtures/parity/legacy/errors__oauth_token_invalid_client.json create mode 100644 tests/fixtures/parity/legacy/errors__oauth_token_invalid_grant.json create mode 100644 tests/fixtures/parity/legacy/errors__oauth_token_missing_grant_type.json create mode 100644 tests/fixtures/parity/legacy/errors__oauth_token_refresh_invalid_grant.json create mode 100644 tests/fixtures/parity/legacy/errors__oauth_token_unsupported_grant_type.json create mode 100644 tests/fixtures/parity/legacy/errors__web_assess_payment_required.json create mode 100644 tests/fixtures/parity/legacy/errors__web_assess_signup_required.json create mode 100644 tests/fixtures/parity/legacy/errors__web_review_rate_limited.json create mode 100644 tests/fixtures/parity/legacy/review__422_webhook_secret_missing.json create mode 100644 tests/fixtures/parity/legacy/review__delete_not_a_route.json create mode 100644 tests/fixtures/parity/legacy/verify__delete_200.json create mode 100644 tests/fixtures/parity/legacy/verify__delete_404.json create mode 100644 tests/fixtures/parity/legacy/verify__delete_not_yours_404.json create mode 100644 tests/fixtures/parity/legacy/verify__webhook_secret_missing_422.json create mode 100644 tests/fixtures/parity/legacy/webhook__test_fire.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_completed_sparse_result.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_failed_error_none.json create mode 100644 tests/fixtures/parity/legacy/webhook__verification_needs_input_hint_none.json create mode 100644 tests/fixtures/parity/pickles.json create mode 100644 tests/fixtures/parity/schemas.json create mode 100644 tests/parity_static.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 7770c25..02166a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,11 @@ on upgrade. - **Reads both response shapes.** The API is adding a newer, dated response shape that gives each field one name across every endpoint. This release still asks for the original shape (it sends the same `X-Lenz-API-Version` - as before), and every model now reads either shape. The newer names are - attributes now, filled from whichever shape arrives: + as before), and every model now reads either shape. A body is read as the + newer shape only when it carries something only that shape has; every other + body is parsed exactly as before (same fields, values, dump, `repr`, + `exclude_unset`, schema and pickle). The newer names are read-only + properties, computed from whichever shape arrived, not model fields: - `ExtractedClaims.claims`: every claim found, always a list, each an `ExtractedClaim` with `claim` and (with `locate=True`) `positions`. - `AssessClaim.status` (`"completed"` / `"failed"`), `AssessClaim.failure` @@ -29,10 +32,13 @@ on upgrade. `ReviewVerification`. - `FailureBlock.code` and `FailureBlock.detail`; `ReviewAssessment.more_claims`; `ReviewSummary.claims_found`, - `claim_limit_exceeded` and `citation_limit_exceeded`; + `claim_limit_exceeded` (``None`` from the original shape, which says only + that the limit was reached: read `more_claims` there) and + `citation_limit_exceeded`; `CitecheckSummary.citation_limit_exceeded`. - - Webhooks: `event_id` on every event, `VerificationFailed.failure`, - `VerificationNeedsInput.reason` and `.claims`. A review or citation-check + - Webhooks: an `event_id` property on every event, + `VerificationFailed.failure`, `VerificationNeedsInput.reason` and + `.claims` (properties: `dataclasses.asdict` and `repr` are unchanged). A review or citation-check event in the newer shape carries no `task_id` (it reads `""`; deduplicate on `event_id`, as before). `parse_webhook` and `LenzWebhooks.parse` read the newer envelope too (`event`, `event_id`, @@ -54,8 +60,8 @@ on upgrade. `FailureBlock.failure_reason`; `ReviewAssessment.error_code` / `hint` / `identified_claims`; `claim_limit_reached` / `citation_limit_reached`; `Usage.quota_resets_at` and the `verify` / `ask` / `assess` blocks (computed - from `credits` and `costs` when a response leaves them out). They are marked - deprecated in the JSON schema; reading them does not warn. "Nothing + from `credits` and `costs` when a response leaves them out). Reading them + does not warn, and the JSON schema is unchanged. "Nothing checkable" keeps its old spelling in the old fields (`not_a_claim`, `no_claim`) and reads `no_checkable_claim` in the new ones; `ExtractedClaims.status` keeps `not_a_claim`. @@ -69,9 +75,20 @@ on upgrade. changes now; leaving it out keeps that meaning on later API versions, where `""` means "no webhook". `review` and `citecheck` send `webhook_url` exactly as before (there `""` means "no webhook"). -- `model_dump()` returns the shape the server sent: attributes filled in from - the other shape are left out, so an original-shape response dumps exactly as - before. +- A newer-shape body's `model_dump()` holds what the server sent plus the + original fields filled in from it. + +### Before the SDK asks for the newer shape + +This release only reads the newer shape; it keeps asking for the original +one. Two things to settle before a release sends the newer date: + +- A 422's `code` there is the server's new one (`blank_input` where the + original said `blank_item`, `validation_error` where it said nothing), and + its `message` is the server's sentence, not the field list. +- `lenz verify --json` on a `needs_input` run prints each option as the model + dumps it: from the newer shape that is `{claim, domain, text}`, not + `{text, domain}`. ### Correction @@ -81,6 +98,9 @@ on upgrade. They are deprecated and kept for existing callers; the API keeps sending them to integrations built against its original shape. Their deprecation warnings no longer name a date. +- **`TaskStatus.candidates` and `similar_claims` are not removed on + 2026-11-29** either (2.18.0 said so). They are deprecated, always empty, and + kept. ## [2.20.0] - 2026-10-05 diff --git a/README.md b/README.md index 502a192..02cc3ae 100644 --- a/README.md +++ b/README.md @@ -492,8 +492,9 @@ older ones keep working, with the meaning they always had: | `Usage.credits` and `Usage.costs` | the `verify` / `ask` / `assess` blocks, `quota_resets_at` | "Nothing checkable" is `no_checkable_claim` in the newer names; the older -fields keep their own spelling (`not_a_claim`, `no_claim`). `model_dump()` -returns the shape the server sent. +fields keep their own spelling (`not_a_claim`, `no_claim`). The newer names +are read-only properties, so an original-shape response parses, dumps and +compares exactly as before. ### A suggested rewrite (`suggested_rewrite`) diff --git a/openapi.json b/openapi.json index 925314c..603db53 100644 --- a/openapi.json +++ b/openapi.json @@ -411,7 +411,7 @@ } } }, - "description": "Return the calling account's credit balance and what it can still buy.\n\n**``credits`` is the balance.** One pool funds every billable capability,\nat the weights in ``costs`` \u2014 today ``verify`` 10, ``assess`` 1, ``ask`` 1.\nIt has two buckets: the monthly allowance for the current ``plan``, which\nresets at ``resets_at``, and non-expiring ``extra`` credits from grants and\ntop-ups, spent only once the allowance is gone. ``remaining`` is the sum,\nand is what a call is actually checked against.\n\n``credits.bonus`` is the deprecated old name of ``credits.extra``, the same\nnumber, kept for existing callers with the fields below. Read ``extra``.\n\n``plan`` is the stable slug to branch on; ``plan_label`` is the same tier\nas display copy (\"Pro\"). Two fields rather than one humanised\nstring, so a reworded label cannot break a client comparing tiers.\nThe Pro plan's ``plan`` is ``pro``; it read ``developer`` before\n2026-09-15 (#664), while ``plan_label`` already read \"Pro\".\n\n**The per-capability blocks are deprecated.** ``verify`` / ``ask`` /\n``assess`` are **projections** of that one pool into each capability's own\nunit \u2014 \"how many of these could I still make\" \u2014 not separate allowances.\nSpending on one moves all of them, and they are floor divisions, so a\nverify block ticks once per 10 credits spent anywhere.\n\nThey are kept for existing callers, with the per-block ``credits`` alias.\nNew code derives them instead::\n\n remaining = credits.remaining // costs[capability]\n total = credits.total // costs[capability]\n used = total - remaining\n\nTwo capabilities at the same price emit identical blocks \u2014 ``ask`` and\n``assess`` are both 1 credit \u2014 which is the clearest sign the shape\ndescribes an allowance that no longer exists.\n\n``bonus`` in each block is ``credits.extra`` in that capability's unit. The\nolder key ``credits`` is its deprecated alias, on the same date.\n\n``costs`` is one entry per capability at its DEFAULT price. Prices that\ndepend on a request parameter live in ``cost_options``, nested capability\n\u2192 parameter \u2192 value \u2014 ``{\"verify\": {\"depth\": {\"standard\": 10, \"low\": 5}}}``.\nTwo maps rather than a flat one with a ``verify_low`` key, so a future\ntuning parameter nests instead of adding an entry that reads like a fifth\ncapability. Every capability in ``cost_options`` also appears in ``costs``\nat its default, so reading only ``costs`` is always correct.\n\n``extract`` is free at the pool (``costs.extract`` is 0) and is bounded by\na per-account daily fair-use cap instead, reported separately here and\nrejected with 429 rather than 402.", + "description": "Return the calling account's credit balance and what it can still buy.\n\n**``credits`` is the balance.** One pool funds every billable capability,\nat the weights in ``costs`` \u2014 today ``verify`` 10, ``assess`` 1, ``ask`` 1.\nIt has two buckets: the monthly allowance for the current ``plan``, which\nresets at ``resets_at``, and non-expiring ``extra`` credits from grants and\ntop-ups, spent only once the allowance is gone. ``remaining`` is the sum,\nand is what a call is actually checked against.\n\n``credits.bonus`` is the deprecated old name of ``credits.extra``, the same\nnumber, kept for existing callers with the fields below. Read ``extra``.\n\n``plan`` is the stable slug to branch on; ``plan_label`` is the same tier\nas display copy (\"Pro\"). Two fields rather than one humanised\nstring, so a reworded label cannot break a client comparing tiers.\nThe Pro plan's ``plan`` is ``pro``; it read ``developer`` before\n2026-09-15 (#664), while ``plan_label`` already read \"Pro\".\n\n**The per-capability blocks are deprecated.** ``verify`` / ``ask`` /\n``assess`` are **projections** of that one pool into each capability's own\nunit \u2014 \"how many of these could I still make\" \u2014 not separate allowances.\nSpending on one moves all of them, and they are floor divisions, so a\nverify block ticks once per 10 credits spent anywhere.\n\nThey are kept for existing callers, with the per-block ``credits`` alias.\nNew code derives them instead::\n\n remaining = credits.remaining // costs[capability]\n total = credits.total // costs[capability]\n used = total - remaining\n\nTwo capabilities at the same price emit identical blocks \u2014 ``ask`` and\n``assess`` are both 1 credit \u2014 which is the clearest sign the shape\ndescribes an allowance that no longer exists.\n\n``bonus`` in each block is ``credits.extra`` in that capability's unit. The\nolder key ``credits`` is its deprecated alias.\n\n``costs`` is one entry per capability at its DEFAULT price. Prices that\ndepend on a request parameter live in ``cost_options``, nested capability\n\u2192 parameter \u2192 value \u2014 ``{\"verify\": {\"depth\": {\"standard\": 10, \"low\": 5}}}``.\nTwo maps rather than a flat one with a ``verify_low`` key, so a future\ntuning parameter nests instead of adding an entry that reads like a fifth\ncapability. Every capability in ``cost_options`` also appears in ``costs``\nat its default, so reading only ``costs`` is always correct.\n\n``extract`` is free at the pool (``costs.extract`` is 0) and is bounded by\na per-account daily fair-use cap instead, reported separately here and\nrejected with 429 rather than 402.", "tags": [ "Account" ], diff --git a/src/lenz_io/cli/render.py b/src/lenz_io/cli/render.py index 753cfca..80e7e05 100644 --- a/src/lenz_io/cli/render.py +++ b/src/lenz_io/cli/render.py @@ -109,12 +109,15 @@ def render_extract(out: Output, result: ExtractedClaims) -> None: if out.json_mode: out.emit_json(_model_json(result)) return - # ``claims`` is the whole list, from either response shape (the model - # builds it from ``claim`` + ``identified_claims`` when that is what the - # server sent). Blank and repeated entries are dropped. - claims: list[str] = [] - for item in result.claims: - c = (item.claim or "").strip() + # The server splits a claim set across two fields: the primary claim lands + # in ``claim`` and any extras in ``identified_claims``. Neither alone is the + # full list — the primary is usually NOT echoed into ``identified_claims`` — + # so render the union so the primary is never dropped (and the count is + # right). Single-claim input → just ``claim``. + primary = (getattr(result, "claim", "") or "").strip() + claims = [primary] if primary else [] + for c in result.identified_claims or []: + c = (c or "").strip() if c and c not in claims: claims.append(c) if len(claims) > 1: @@ -148,7 +151,7 @@ def _render_positions(out: Output, result: ExtractedClaims, claim: str, *, inden input, where there is nothing to index) and the passage itself. The passage is the user's own text, so it prints with ``markup=False``. """ - for loc in result.claims: + for loc in result.locations or []: if (loc.claim or "").strip() != claim: continue for pos in loc.positions or []: @@ -168,10 +171,9 @@ def render_assess(out: Output, result: AssessResponse) -> None: return for c in claims: color = _VERDICT_COLOR.get(c.verdict, "white") - # A failed row (list form) names its cause in place of the confidence, - # which is meaningless there. ``error_code`` is the cause in its - # original spelling, from either response shape. - detail = c.error_code if c.status == "failed" and c.error_code else c.confidence + # An Error row (list form) names its cause in place of the confidence, + # which is meaningless there. + detail = c.error_code if c.verdict == "Error" and c.error_code else c.confidence out.console.print(f"[{color}]{c.verdict or '?'}[/{color}] ({detail}) — {c.claim}") # The reviewers' notes, as plain text: `markup=False` because the # words are a model's, and a stray "[bold]" in them is not ours. @@ -179,9 +181,9 @@ def render_assess(out: Output, result: AssessResponse) -> None: out.console.print(f" {c.rationale}", markup=False, highlight=False) if c.dissent: out.console.print(f" One reviewer disagreed: {c.dissent}", markup=False, highlight=False) - if c.more_claims: + if c.identified_claims: out.console.print(" [dim]also found:[/dim]") - for other in c.more_claims: + for other in c.identified_claims: out.console.print(f" • {other}") if c.hint: out.console.print(f" [dim]{c.hint}[/dim]") @@ -393,7 +395,7 @@ def render_task_status(out: Output, st: TaskStatus, *, task_id: str = "") -> Non if st.claims: out.console.print("[dim]claims found:[/dim]") for i, claim in enumerate(st.claims, 1): - out.console.print(f" {i}. {claim.claim}") + out.console.print(f" {i}. {claim.text}") ref = task_id or "" # Non-interactive resolution (agents/scripts): `--claim` picks by index # and `--detach` returns the spawned task_id(s) without blocking. Drop diff --git a/src/lenz_io/cli/verify.py b/src/lenz_io/cli/verify.py index f0ca5a5..8373375 100644 --- a/src/lenz_io/cli/verify.py +++ b/src/lenz_io/cli/verify.py @@ -198,7 +198,7 @@ def _poll( # Sub-claims inherit the parent submission's depth server-side # (/select reads it off the task meta), so nothing to send here. items = client.select(task_id, claims=texts).items - picks = [(it.task_id, it.claim or txt) for it, txt in zip(items, texts, strict=True)] + picks = [(it.task_id, it.claim_text or txt) for it, txt in zip(items, texts, strict=True)] # detach, or >1 claim → batch path; exactly one → keep the # single-verdict flow (nicer than a 1-row table). if detach or len(picks) > 1: @@ -256,7 +256,7 @@ def _resolve_multi_claim(out: Output, task_id: str, st: TaskStatus, selection: l Otherwise json mode emits the needs_input object and exits 3 (never hangs on a prompt that can't happen); a TTY shows the checkbox picker. """ - options = [c.claim for c in st.claims] + options = [c.text for c in st.claims] if selection is not None: return [options[i] for i in _selection_to_indices(selection, len(options))] if out.json_mode: @@ -393,8 +393,8 @@ def _emit_needs_input(out: Output, task_id: str, st: TaskStatus) -> None: "hint": st.hint, "task_id": task_id, "claims": [c.model_dump(mode="json") for c in st.claims], - # Deprecated compatibility keys, always empty; removal is planned - # for 2026-11-29 with the ``TaskStatus`` fields they mirrored. + # Deprecated compatibility keys, always empty; kept, like the + # ``TaskStatus`` fields they mirror. "candidates": [], "similar": [], } diff --git a/src/lenz_io/client.py b/src/lenz_io/client.py index b45141e..999648f 100644 --- a/src/lenz_io/client.py +++ b/src/lenz_io/client.py @@ -215,6 +215,18 @@ def _batch_item_body(item: Any) -> Any: return body +def _extracted(body: Any, *, locate: bool | None) -> ExtractedClaims: + """``/extract``'s answer. A newer-shape body (``claims``, no + ``identified_claims``) that located every claim away answers ``claims: + []``; the original field for that was ``locations=[]``, which only the + request (``locate=True``) can tell apart from "nothing found".""" + out = ExtractedClaims.model_validate(body) + newer = isinstance(body, dict) and "claims" in body and "identified_claims" not in body + if newer and locate and not body["claims"] and out.status == "not_a_claim" and out.locations is None: + out.locations = [] + return out + + #: An async job the poll loop waits on: a review or a citation check. _Job = TypeVar("_Job", ReviewFull, Citecheck) @@ -985,21 +997,19 @@ def verify_batch_and_wait( terminal, timed_out, gone = self._poll_to_terminal(ids, timeout, on_progress) results: list[BatchItemResult] = [] - # Built with ``claim_text`` so ``model_dump()`` keeps the keys it has - # always had; ``BatchItemResult.claim`` reads the same string. for it in accepted.items: # preserve input order status = terminal.get(it.task_id) if it.task_id in gone: # Removed by the account's retention period (410): terminal, # with no status to carry. - results.append(BatchItemResult(task_id=it.task_id, claim_text=it.claim, status="failed")) + results.append(BatchItemResult(task_id=it.task_id, claim_text=it.claim_text, status="failed")) elif not it.task_id or it.task_id in timed_out or status is None: - results.append(BatchItemResult(task_id=it.task_id, claim_text=it.claim, status="timeout")) + results.append(BatchItemResult(task_id=it.task_id, claim_text=it.claim_text, status="timeout")) elif status.status == "completed" and status.result is not None: results.append( BatchItemResult( task_id=it.task_id, - claim_text=it.claim, + claim_text=it.claim_text, status="completed", verification=status.result, status_detail=status, @@ -1007,12 +1017,14 @@ def verify_batch_and_wait( ) elif status.status == "needs_input": results.append( - BatchItemResult(task_id=it.task_id, claim_text=it.claim, status="needs_input", status_detail=status) + BatchItemResult( + task_id=it.task_id, claim_text=it.claim_text, status="needs_input", status_detail=status + ) ) else: # failed, or completed-without-result (treated as failed). results.append( - BatchItemResult(task_id=it.task_id, claim_text=it.claim, status="failed", status_detail=status) + BatchItemResult(task_id=it.task_id, claim_text=it.claim_text, status="failed", status_detail=status) ) return results @@ -1528,8 +1540,6 @@ def _verification_from_terminal(self, status: TaskStatus, task_id: str) -> Verif ) # failed. Server sends the diagnostic under ``error``; fall back to the # legacy fields for resilience. - # ``failure.detail`` is the sentence in the newer response shape; - # ``error`` carries the original one (and is filled from the block). detail = status.error or status.failure_detail or status.failure_reason or "unknown" if status.retryable: fix = "Transient provider outage — retry the same request after a short wait." @@ -1668,7 +1678,7 @@ def _extract( if idempotency_key: headers["Idempotency-Key"] = idempotency_key body = self._request("POST", "/extract", json=payload, timeout=timeout, headers=headers) - return ExtractedClaims.model_validate(body) + return _extracted(body, locate=locate) def _assess( self, diff --git a/src/lenz_io/errors.py b/src/lenz_io/errors.py index 47c9583..2f6579e 100644 --- a/src/lenz_io/errors.py +++ b/src/lenz_io/errors.py @@ -569,23 +569,29 @@ def map_response_to_error( # The generic 4xx advice ("retry; file an issue") is wrong for both: # the server's own hint says what to do, with a class default behind it. # A failed run states its cause flat in the original response shape - # and in one ``failure`` block in the newer one; read both, flat first. + # and in one ``failure`` block in the newer one. The block is read only + # for a newer-shape body, and only where the flat key is absent. raw_failure = parsed.get("failure") - failure: dict[str, Any] = raw_failure if isinstance(raw_failure, dict) else {} + newer = isinstance(raw_failure, dict) and "failure_reason" not in parsed + failure: dict[str, Any] = raw_failure if newer and isinstance(raw_failure, dict) else {} + + def _read(key: str, block_key: str) -> Any: + return parsed[key] if key in parsed else failure.get(block_key) + err.task_id = _opt_str(parsed.get("task_id")) - err.hint = _opt_str(parsed.get("hint")) or _opt_str(failure.get("hint")) + err.hint = _opt_str(_read("hint", "hint")) if isinstance(err, LenzVerificationNotReadyError): err.status = _opt_str(parsed.get("status")) err.fix = err.hint or "Wait for the run with client.wait(task_id), then read its result." else: - reason = _opt_str(parsed.get("failure_reason")) or _opt_str(failure.get("code")) + reason = _opt_str(_read("failure_reason", "code")) # The original spelling of "nothing checkable" on a verification. - err.failure_reason = "not_a_claim" if reason == "no_checkable_claim" else reason - err.failure_class = _opt_str(parsed.get("failure_class")) or _opt_str(failure.get("failure_class")) + err.failure_reason = "not_a_claim" if newer and reason == "no_checkable_claim" else reason + err.failure_class = _opt_str(_read("failure_class", "failure_class")) # Only a real boolean is a retry signal, as in the wait path. - retryable = parsed.get("retryable", failure.get("retryable")) + retryable = _read("retryable", "retryable") err.retryable = retryable if isinstance(retryable, bool) else None - err.doc_url = _opt_str(parsed.get("docs_url")) or _opt_str(failure.get("docs_url")) or err.doc_url + err.doc_url = _opt_str(_read("docs_url", "docs_url")) or err.doc_url if err.hint: err.fix = err.hint elif err.retryable: @@ -622,9 +628,9 @@ def map_response_to_error( # sending null precisely so "unknown" stays distinguishable from # "zero". Collapsing that here would throw the distinction away. err.remaining = _opt_int(parsed.get("remaining")) - if err.remaining is None and "remaining" not in parsed and "requested" not in parsed: - # A body without the capability figure (the newer response shape - # on some endpoints): the pool divided by this one call's price. + if "remaining" not in parsed and "requested" not in parsed and "doc_url" not in parsed and "docs_url" in parsed: + # A newer-shape body (``docs_url``) without the capability figure: + # the pool divided by this one call's price. pool, price = _opt_int(parsed.get("credits_remaining")), _opt_int(parsed.get("cost")) if pool is not None and price: err.remaining = pool // price @@ -649,9 +655,17 @@ def map_response_to_error( elif isinstance(err, LenzRateLimitError): err.limit = _opt_int(parsed.get("limit")) err.reset_in_seconds = _opt_int(parsed.get("reset_in_seconds")) - if err.reset_in_seconds is None and code not in _IN_FLIGHT_429_CODES: - # The newer response shape names every wait ``retry_after``. The - # in-flight refusals never carried ``reset_in_seconds``. + if ( + "reset_in_seconds" not in parsed + and "retry_after_seconds" not in parsed + and "retry_after" in parsed + and "docs_url" in parsed + and "doc_url" not in parsed + and code not in _IN_FLIGHT_429_CODES + ): + # A newer-shape body (``docs_url``) names every wait + # ``retry_after``. The in-flight refusals never carried + # ``reset_in_seconds``. err.reset_in_seconds = _opt_int(parsed.get("retry_after")) rl_upgrade_url = parsed.get("upgrade_url") err.upgrade_url = rl_upgrade_url if isinstance(rl_upgrade_url, str) else "" diff --git a/src/lenz_io/models.py b/src/lenz_io/models.py index d6146d9..c9fc1a9 100644 --- a/src/lenz_io/models.py +++ b/src/lenz_io/models.py @@ -12,68 +12,17 @@ - ``claim`` : str — the framed claim text - ``verdict`` : str — "True" | "Mostly True" | "Mixed" | "Mostly False" | "False" | "Error" - ("Error": an ``assess`` row with ``status == "failed"``) - ``confidence`` : str — "high" | "medium" | "low" (categorical) - ``lenz_score`` : int | None - 1-10 integer (deep / list; /assess omits) """ from __future__ import annotations -import functools -from collections.abc import Callable, ItemsView, KeysView, ValuesView +from collections.abc import ItemsView, KeysView, ValuesView from datetime import datetime, timezone from typing import Any, Literal -from pydantic import ( - BaseModel, - ConfigDict, - Field, - PrivateAttr, - SerializerFunctionWrapHandler, - model_serializer, - model_validator, -) - -#: Where a validator lists the attributes it filled in that the response did -#: not carry. ``_Lax`` moves it to a private attribute; ``model_dump()`` leaves -#: those attributes out, so a dump is always the shape the server sent. -_DERIVED_KEY = "__lenz_derived__" - - -def _reads_both(*new_fields: str, always_hide: bool = False) -> Callable[[Callable[..., Any]], Callable[..., Any]]: - """Mark what a ``_read_both_shapes`` validator derived, so ``model_dump()`` - shows the shape the server sent. - - ``new_fields`` are the attributes this release added for the newer - response shape. Hidden from a dump: each of them the input did not carry - (so an original-shape response dumps exactly as it did before this - release), and, on a newer-shape input (one carrying any of them, or any - input with ``always_hide``), every attribute the input did not carry. A - value the validator rewrote (a failed row's ``verdict``) dumps as sent. - """ - - def wrap(fn: Callable[..., Any]) -> Callable[..., Any]: - @functools.wraps(fn) - def inner(cls: Any, data: Any) -> Any: - out = fn(cls, data) - if not isinstance(data, dict) or not isinstance(out, dict): - return out - hidden = {k for k in new_fields if k not in data} - if always_hide or any(k in data for k in new_fields): - hidden |= {k for k in out if k not in data} - hidden |= {k for k in cls.model_fields if k not in data} - rewritten = { - k: v - for k, v in data.items() - if k in out and not isinstance(v, (dict, list)) and out[k] is not v and out[k] != v - } - if not hidden and not rewritten: - return out - return {**out, _DERIVED_KEY: {"hidden": sorted(hidden), "sent": rewritten}} - - return inner - - return wrap +from pydantic import BaseModel, ConfigDict, Field, model_validator class _Lax(BaseModel): @@ -87,41 +36,25 @@ class _Lax(BaseModel): model_config = ConfigDict(extra="allow") - # The attributes filled in from the other response shape (see - # ``_reads_both``): readable, never dumped. - _lenz_derived: frozenset[str] = PrivateAttr(default_factory=frozenset) - _lenz_sent: dict[str, Any] = PrivateAttr(default_factory=dict) - - @model_validator(mode="after") - def _collect_derived(self) -> Any: - extra = self.__pydantic_extra__ - if extra and _DERIVED_KEY in extra: - marks = extra.pop(_DERIVED_KEY) - self._lenz_derived = frozenset(marks["hidden"]) - self._lenz_sent = dict(marks["sent"]) - return self - - @model_serializer(mode="wrap") - def _dump_as_sent(self, handler: SerializerFunctionWrapHandler) -> Any: - data = handler(self) - if isinstance(data, dict): - for key in self._lenz_derived: - data.pop(key, None) - for key, value in self._lenz_sent.items(): - if key in data: - data[key] = value - return data - # ── Reading both response shapes ───────────────────────────────────────── # # The API is gaining a second, dated response shape that renames a handful of # fields (``claim_text`` -> ``claim``, ``modified_at`` -> ``completed_at``, a # failed item's ``error`` / ``error_code`` / ``failure_reason`` -> one -# ``failure`` block, ...). This release still asks for the original shape, but -# every model reads either one: the new name is a first-class attribute, and -# every old attribute keeps its old meaning, computed from whichever shape -# arrived. The helpers below are the shared rules. +# ``failure`` block, ...). This release still asks for the original shape. +# +# Two rules keep existing code exactly as it was: +# +# * A body is treated as the newer shape only when it carries something only +# that shape has. Every other body is parsed exactly as before: same fields, +# same values, same dump, same ``exclude_unset``. +# * A newer-shape body gets the original fields filled in, with their original +# meaning, from the newer ones (only where the body does not carry them). +# +# The newer names are read-only properties, computed from either shape: they +# are not model fields, so ``repr``, ``model_dump()``, equality and pickling of +# an original-shape object are unchanged. #: The one code for "the input holds nothing that can be checked", in the #: newer response shape. The original shape spells it per endpoint: @@ -140,6 +73,12 @@ def _old_code(code: Any, old: str) -> Any: return old if code in (NO_CHECKABLE_CLAIM, *_OLD_NO_CLAIM_CODES) else code +def _is_newer(data: Any, has: str, lacks: str) -> bool: + """A dict carrying ``has`` (a key only the newer shape sends) and not + ``lacks`` (its original-shape counterpart).""" + return isinstance(data, dict) and has in data and lacks not in data + + def _utc_day(iso: Any) -> Any: """The UTC calendar day of an ISO-8601 string, or ``None``.""" if not isinstance(iso, str) or not iso: @@ -162,30 +101,24 @@ def _modified_at_from(created_at: Any, completed_at: Any) -> str | None: return str(completed_at) -def _with_completion_times(data: Any) -> Any: - """Fill ``completed_at`` and ``modified_at`` from whichever one arrived. - - ``modified_at`` from ``completed_at``: the original later-calendar-day - rule. ``completed_at`` from ``modified_at``: exact when ``modified_at`` is - set; when it is null (a same-day completion) the original shape does not - say when the verification completed, so ``completed_at`` stays ``None``. - """ - if not isinstance(data, dict): - return data - if "completed_at" in data and "modified_at" not in data: +def _fill_modified_at(data: Any) -> Any: + """A newer-shape verification (``completed_at``, no ``modified_at``): + add the original ``modified_at``.""" + if _is_newer(data, "completed_at", "modified_at"): return {**data, "modified_at": _modified_at_from(data.get("created_at"), data.get("completed_at"))} - if "modified_at" in data and "completed_at" not in data: - return {**data, "completed_at": data.get("modified_at")} return data -def _mirror(data: dict[str, Any], new: str, old: str) -> dict[str, Any]: - """Copy a field across a plain rename, in whichever direction is missing.""" - if new in data and old not in data: - return {**data, old: data[new]} - if old in data and new not in data: - return {**data, new: data[old]} - return data +def _fill(data: dict[str, Any], **values: Any) -> dict[str, Any]: + """``data`` with each of ``values`` added where the key is missing.""" + return {**{k: v for k, v in values.items() if k not in data}, **data} + + +def _sent(model: BaseModel, key: str) -> Any: + """The value the server sent under ``key`` when it is not a field of this + release's model (a newer-shape key), else ``None``.""" + extra = model.__pydantic_extra__ or {} + return extra.get(key) #: Closed set of failure causes on a ``failed`` verification, mirroring the @@ -264,22 +197,23 @@ class Audit(_Lax): class CandidateClaim(_Lax): - """One of multiple distinct claims framing found in the submitted text. - - ``claim`` is the claim's text. ``text`` is its older name, the same - string, kept for existing code (deprecated; either shape fills both). - """ + """One of multiple distinct claims framing found in the submitted text.""" - claim: str = "" - #: Deprecated: the same string as :attr:`claim`. - text: str = Field(default="", json_schema_extra={"deprecated": True}) + text: str = "" domain: str = "" @model_validator(mode="before") @classmethod - @_reads_both("claim") - def _read_both_shapes(cls, data: Any) -> Any: - return _mirror(data, "claim", "text") if isinstance(data, dict) else data + def _read_newer_shape(cls, data: Any) -> Any: + if _is_newer(data, "claim", "text"): + return _fill(data, text=data["claim"]) + return data + + @property + def claim(self) -> str: + """The option's claim (``text`` is its older name, the same string).""" + sent = _sent(self, "claim") + return sent if isinstance(sent, str) else self.text class EntityRef(_Lax): @@ -400,9 +334,8 @@ class Verification(_Lax): endpoint, and the webhook payload. The verdict block is FLAT at top level (was nested ``Verdict`` object - pre-unify). ``created_at`` and ``completed_at`` are its timestamps - (``modified_at`` is the deprecated older one) — editorial - ``published_at`` is internal-only. + pre-unify). ``created_at`` + ``modified_at`` are the only timestamp + fields on the API surface — editorial ``published_at`` is internal-only. 1.1.0: dropped ``url`` and ``visibility``. API claims are private by default and referenced by ``verification_id`` only. Cache-hit on @@ -451,13 +384,7 @@ class Verification(_Lax): sources: list[Source] = Field(default_factory=list) audit: Audit = Field(default_factory=Audit) created_at: str | None = None - #: When the verification completed. In the original response shape it is - #: known only through ``modified_at``: set when that is, ``None`` on a - #: same-day completion (and on servers that send neither). - completed_at: str | None = None - #: Deprecated: the completion time when it falls on a later UTC calendar - #: day than ``created_at``, else ``None``. Read :attr:`completed_at`. - modified_at: str | None = Field(default=None, json_schema_extra={"deprecated": True}) + modified_at: str | None = None # Output language (ISO 639-1). Always populated by the server when # the SDK is fresh; defaulted to ``'en'`` for resilience against # older cached payloads that lack the field. @@ -474,9 +401,16 @@ class Verification(_Lax): @model_validator(mode="before") @classmethod - @_reads_both("completed_at") - def _read_both_shapes(cls, data: Any) -> Any: - return _with_completion_times(data) + def _read_newer_shape(cls, data: Any) -> Any: + return _fill_modified_at(data) + + @property + def completed_at(self) -> str | None: + """When the verification completed. From the original response shape it + is known only through ``modified_at``: set when that is, ``None`` on a + same-day completion.""" + sent = _sent(self, "completed_at") + return sent if isinstance(sent, str) else self.modified_at class VerificationListItem(_Lax): @@ -498,18 +432,22 @@ class VerificationListItem(_Lax): # A suggested rewrite of ``claim``. See ``Verification.suggested_rewrite``. suggested_rewrite: str | None = None created_at: str | None = None - #: See ``Verification.completed_at``. - completed_at: str | None = None - #: Deprecated. See ``Verification.modified_at``. - modified_at: str | None = Field(default=None, json_schema_extra={"deprecated": True}) + modified_at: str | None = None # Output language (ISO 639-1). See ``Verification.language``. language: str = "en" @model_validator(mode="before") @classmethod - @_reads_both("completed_at") - def _read_both_shapes(cls, data: Any) -> Any: - return _with_completion_times(data) + def _read_newer_shape(cls, data: Any) -> Any: + return _fill_modified_at(data) + + @property + def completed_at(self) -> str | None: + """When the verification completed. From the original response shape it + is known only through ``modified_at``: set when that is, ``None`` on a + same-day completion.""" + sent = _sent(self, "completed_at") + return sent if isinstance(sent, str) else self.modified_at class VerificationList(_Lax): @@ -582,9 +520,7 @@ class ClaimLocation(_Lax): #: from lenz_io import ExtractStatus #: #: - ``ready`` — claims were found (and, with a ``focus``, at least one matched). -#: - ``not_a_claim`` — the text holds no verifiable factual claim at all (the -#: newer response shape spells it ``no_checkable_claim``; this release -#: reads both as ``not_a_claim``). +#: - ``not_a_claim`` — the text holds no verifiable factual claim at all. #: - ``no_match`` — claims were found, but none fall within the ``focus``. #: #: A DOCUMENTATION constant, not a guarantee. The model field stays ``str``, @@ -606,37 +542,30 @@ class ClaimLocation(_Lax): class ExtractedClaim(ClaimLocation): """One claim ``/extract`` found: ``claim``, and with ``locate=True`` its ``positions`` in the text (``None`` when the call did not locate, or the - claims could not be located).""" + claims could not be located). Returned by ``ExtractedClaims.claims``.""" class ExtractedClaims(_Lax): """Output of ``POST /extract``. - ``claims`` is every claim found, most check-worthy first, always a list - (one entry for one claim, ``[]`` for none). With ``locate=True`` each - entry's ``positions`` says where the text makes it. - ``status`` is one of ``ExtractStatus``: ``ready``, ``not_a_claim``, or — when a ``focus`` was given and no claim fell within it — ``no_match``. - ``no_match`` is a successful answer, not an error: ``claims`` is empty - and the unfocused list is never substituted for it. In this release - ``status`` keeps the ``not_a_claim`` spelling whichever response shape - arrived (the newer shape spells it ``no_checkable_claim``). - - Deprecated, kept with their original meaning: ``claim`` is the first - claim (``""`` for none), ``identified_claims`` the whole list when there - are two or more (``[]`` for one), and ``locations`` the ``ClaimLocation`` - list of a located call (``None`` when ``locate`` was not set, when the - extraction found no claims, or when the claims could not be located). - Read ``claims`` instead: it is filled from either response shape. + ``no_match`` is a successful answer, not an error: ``identified_claims`` + is empty and the unfocused list is never substituted for it. + + ``locations`` is set only on a call made with ``locate=True``: one + ``ClaimLocation`` per returned claim, in the order of + ``identified_claims`` (one entry for a single ``claim``). It is ``[]`` + when every claim was left out (``status`` is then ``"not_a_claim"``), + and ``None`` when ``locate`` was not set, when the extraction found no + claims, or when the + claims could not be located (the list is then returned unfiltered). + Older servers omit the key; it parses as ``None``. """ status: str = "" - claims: list[ExtractedClaim] = Field(default_factory=list) - #: Deprecated: the first of :attr:`claims`. - claim: str = Field(default="", json_schema_extra={"deprecated": True}) - #: Deprecated: :attr:`claims` when there are two or more, else ``[]``. - identified_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) + claim: str = "" + identified_claims: list[str] = Field(default_factory=list) # Deprecated: always empty since 2026-09-12. Kept because the server # still sends the key. candidate_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) @@ -644,84 +573,43 @@ class ExtractedClaims(_Lax): key_entities: list[ExtractedEntity] = Field(default_factory=list) presumed_intent: str = "" original_input: str = "" - #: Deprecated: the ``positions`` of :attr:`claims`, as one - #: ``ClaimLocation`` per claim. - locations: list[ClaimLocation] | None = Field(default=None, json_schema_extra={"deprecated": True}) + locations: list[ClaimLocation] | None = None @model_validator(mode="before") @classmethod - @_reads_both("claims") - def _read_both_shapes(cls, data: Any) -> Any: - if not isinstance(data, dict): + def _read_newer_shape(cls, data: Any) -> Any: + if not (_is_newer(data, "claims", "identified_claims") and isinstance(data["claims"], list)): return data - out = dict(data) + items = [c for c in data["claims"] if isinstance(c, dict)] + names = [c.get("claim") if isinstance(c.get("claim"), str) else "" for c in items] + located = bool(items) and all(c.get("positions") is not None for c in items) + out = _fill( + data, + claim=names[0] if names else "", + identified_claims=names if len(names) > 1 else [], + locations=[{"claim": n, "positions": c.get("positions")} for n, c in zip(names, items, strict=True)] + if located + else None, + ) if out.get("status") == NO_CHECKABLE_CLAIM: out["status"] = "not_a_claim" - claims = out.get("claims") - if isinstance(claims, list): - # The newer shape: derive the three original fields. - items = [c for c in claims if isinstance(c, dict)] - names = [str(c.get("claim") or "") for c in items] - out.setdefault("claim", names[0] if names else "") - out.setdefault("identified_claims", names if len(names) > 1 else []) - if "locations" not in out: - located = bool(items) and all(c.get("positions") is not None for c in items) - out["locations"] = ( - [{"claim": c.get("claim") or "", "positions": c.get("positions")} for c in items] - if located - else None - ) - return out - # The original shape: build ``claims`` from ``claim`` + ``identified_claims``. - identified = [c for c in out.get("identified_claims") or [] if isinstance(c, str)] - primary = out.get("claim") if isinstance(out.get("claim"), str) else "" - # ``identified_claims`` normally starts with ``claim``; an older server - # sent the extras only, so take the union, ``claim`` first. - names = ([primary] if primary else []) + [c for c in identified if c != primary] - positions: dict[str, Any] = {} - for loc in out.get("locations") or []: - if isinstance(loc, dict) and isinstance(loc.get("claim"), str): - positions.setdefault(loc["claim"], loc.get("positions")) - out["claims"] = [{"claim": n, "positions": positions.get(n)} for n in names] return out - -class FailureBlock(_Lax): - """Why something failed: a review, one claim's work inside it, a citation - check, an ``assess`` row or a verification. - - ``code`` is the specific cause (an open set, e.g. ``no_checkable_claim``, - ``insufficient_credits``, ``timeout``), ``detail`` one sentence on what - happened (``None`` from the original response shape, which has no such - sentence here), ``failure_class`` the closed :data:`FailureClass`, - ``retryable`` whether resending the same request can help, ``hint`` one - sentence on what to do next and ``docs_url`` where the class is explained. - - ``failure_reason`` is the older name of ``code`` (deprecated), with its - original spelling: ``no_claim`` where ``code`` reads - ``no_checkable_claim``. Either response shape fills both. - """ - - code: str | None = "" - detail: str | None = None - #: Deprecated: :attr:`code`, spelling "nothing checkable" ``no_claim``. - failure_reason: str | None = Field(default="", json_schema_extra={"deprecated": True}) - failure_class: str | None = "" - retryable: bool | None = None - hint: str | None = None - docs_url: str | None = "" - - @model_validator(mode="before") - @classmethod - @_reads_both("code", "detail") - def _read_both_shapes(cls, data: Any) -> Any: - if not isinstance(data, dict): - return data - if "code" in data and "failure_reason" not in data: - return {**data, "failure_reason": _old_code(data["code"], "no_claim")} - if "failure_reason" in data and "code" not in data: - return {**data, "code": _new_code(data["failure_reason"])} - return data + @property + def claims(self) -> list[ExtractedClaim]: + """Every claim found, most check-worthy first: always a list (one entry + for one claim, ``[]`` for none), each with its ``positions`` when the + call located them. Read from either response shape.""" + sent = _sent(self, "claims") + if isinstance(sent, list): + return [ExtractedClaim.model_validate(c) for c in sent if isinstance(c, dict)] + names = list(self.identified_claims) or ([self.claim] if self.claim else []) + if self.claim and self.claim not in names: + names.insert(0, self.claim) + positions: dict[str, Any] = {} + for loc in self.locations or []: + positions.setdefault(loc.claim, loc.positions) + return [ExtractedClaim(claim=n, positions=positions.get(n)) for n in names] class AssessClaim(_Lax): @@ -732,38 +620,29 @@ class AssessClaim(_Lax): ``ClaimDetailOut`` payload at ``GET /api/v1/verifications/{id}`` for callers that want citations and the full audit trail. - ``status`` is ``"completed"`` for a row with a verdict and ``"failed"`` - for one that could not be given a verdict. A failed row stays in - position (one row per item sent on a list call), is not charged, and - says why in ``failure``: ``failure.code`` names the cause and - ``failure.hint`` is one sentence on what to send next — the field to - surface to a human, written per cause. A vague input is assessed on its - most likely reading, which ``claim`` carries. A compound input is - assessed on its main claim; the other claims found in it are listed in - ``more_claims``. - - The original fields keep their meaning whichever response shape - arrived: a failed row reads ``verdict == "Error"`` and - ``confidence == "low"``, its cause is in ``error_code`` (``no_claim`` - where ``failure.code`` reads ``no_checkable_claim``) and its next step in - ``hint``; ``identified_claims`` is ``more_claims``. These fields default - empty so older servers that don't send them still parse. + A row with ``verdict == "Error"`` could not be given a verdict. On a + list call it stays in position (one row per item sent), is not charged, + and says why: ``error_code`` names the cause and ``hint`` is one + sentence on what to send next. ``hint`` is the field to surface to a + human — it is written per cause and stays correct as causes are added. + A vague input is assessed on its most likely reading, which ``claim`` + carries. A compound input is assessed on its main claim; the other + claims found in it are listed in ``identified_claims`` (also with a + ``hint``). These fields default empty so older servers that don't send + them still parse. """ claim: str = "" # Output language (ISO 639-1). Echoes the language requested on the # call, or ``'en'`` when unspecified. Verdict enums always English. language: str = "en" - #: ``"completed"`` (a verdict) or ``"failed"`` (none; see ``failure``). - #: ``""`` only from a server that sent neither a status nor a verdict. - status: str = "" verdict: str = "" # "True" | "Mostly True" | "Mixed" | "Mostly False" | "False" | "Error" confidence: str = "low" # "high" | "medium" | "low" verification_url: str | None = None # ``rationale`` is the reasoning of a reviewer who agrees with the panel's # verdict; ``dissent``, when set, is the reasoning of the reviewer farthest # from it. Both are reviewers' notes, not checked sources; for sourced - # evidence, call ``verify``. Read both as optional: a failed row has + # evidence, call ``verify``. Read both as optional: an ``"Error"`` row has # neither, and a response replayed from before the API added them carries # neither key. rationale: str | None = None @@ -776,69 +655,80 @@ class AssessClaim(_Lax): # check's reasoning and not itself verified: review it, or run it through # ``verify``, before using it. suggested_rewrite: str | None = None - #: Why a failed row has no verdict; ``None`` on a completed row. - #: ``failure.code`` is an OPEN set (``no_checkable_claim`` | - #: ``framing_failed`` | ``upstream_unavailable`` | ``timeout`` today): - #: branch on the ones you know and fall through on the rest. - #: - #: Which are worth resending as-is: ``upstream_unavailable`` (a provider - #: was down) and ``timeout`` (the call ran out of its time budget before - #: this item was done — send fewer items per call to make it less likely). - #: ``framing_failed`` is deterministic, so retrying the same text will not - #: help. ``no_checkable_claim`` wants a different input; read - #: ``failure.hint``. - failure: FailureBlock | None = None - #: Other claims found in the input that were NOT assessed; else empty. - more_claims: list[str] = Field(default_factory=list) - #: Deprecated: ``failure.code`` on a failed row, with "nothing - #: checkable" spelled ``no_claim``; ``None`` on a completed row. - error_code: str | None = Field(default=None, json_schema_extra={"deprecated": True}) + # Only on ``verdict == "Error"`` rows: 'no_claim' | 'framing_failed' | + # 'upstream_unavailable' | 'timeout'. + # + # An OPEN set, deliberately typed ``str`` rather than a Literal: the API + # may add a cause in a minor version, so branch on the ones you know and + # fall through on the rest. + # + # Which are worth resending as-is: 'upstream_unavailable' (a provider was + # down) and 'timeout' (the call ran out of its time budget before this + # item was done — send fewer items per call to make it less likely). + # 'framing_failed' is deterministic, so retrying the same text will not + # help (a provider outage comes back as 'upstream_unavailable' instead). + # 'no_claim' wants a different input; read ``hint``. + error_code: str | None = None # Deprecated: always empty since 2026-09-12, when the ``ambiguous`` cause # that filled it was retired. Kept because the server still sends the key. candidate_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) - #: Deprecated: :attr:`more_claims`. - identified_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) - #: Deprecated: one sentence on what to send next. On a failed row it is - #: ``failure.hint``. The original response shape also set it on a row - #: with other claims found; the newer shape does not. - hint: str | None = Field(default=None, json_schema_extra={"deprecated": True}) + # Other claims found in the input that were NOT assessed; else empty. + identified_claims: list[str] = Field(default_factory=list) + # One sentence on what to send next. Set on every Error row and on a row + # with a non-empty ``identified_claims``; ``None`` on a plain verdict row. + hint: str | None = None @model_validator(mode="before") @classmethod - @_reads_both("status", "failure", "more_claims") - def _read_both_shapes(cls, data: Any) -> Any: - if not isinstance(data, dict): + def _read_newer_shape(cls, data: Any) -> Any: + if not _is_newer(data, "failure", "error_code"): return data - out = _mirror(dict(data), "more_claims", "identified_claims") - status = out.get("status") - verdict = out.get("verdict") - if not status: - status = "failed" if verdict == "Error" else ("completed" if verdict else "") - out["status"] = status - if status == "failed": - # The original meaning of a row with no verdict. - if not verdict: - out["verdict"] = "Error" - if out.get("confidence") is None: - out["confidence"] = "low" - else: - if verdict is None: - out["verdict"] = "" - if out.get("confidence") is None: - out["confidence"] = "low" - failure = out.get("failure") - if isinstance(failure, dict): - code = failure.get("code", failure.get("failure_reason")) - out.setdefault("error_code", _old_code(code, "no_claim")) - out.setdefault("hint", failure.get("hint")) - elif failure is None and status == "failed" and "failure" not in data: - # The original shape: build the block from the row's own fields. - out["failure"] = {"code": _new_code(out.get("error_code") or ""), "hint": out.get("hint")} - return out + out = dict(data) + failed = out.get("status") == "failed" + if out.get("verdict") is None: + out["verdict"] = "Error" if failed else "" + if out.get("confidence") is None: + out["confidence"] = "low" + failure = out.get("failure") if isinstance(out.get("failure"), dict) else {} + return _fill( + out, + error_code=_old_code(failure.get("code"), "no_claim") if failure else None, + hint=failure.get("hint") if failure else None, + identified_claims=out.get("more_claims") or [], + ) + + @property + def status(self) -> str: + """``"completed"`` (a verdict) or ``"failed"`` (none; see ``failure``).""" + sent = _sent(self, "status") + if isinstance(sent, str): + return sent + if self.verdict == "Error": + return "failed" + return "completed" if self.verdict else "" + + @property + def failure(self) -> FailureBlock | None: + """Why a failed row has no verdict (``None`` on a completed row): + ``code`` (``no_checkable_claim`` | ``framing_failed`` | + ``upstream_unavailable`` | ``timeout`` today, an open set) and ``hint``, + one sentence on what to send next.""" + sent = _sent(self, "failure") + if isinstance(sent, dict): + return FailureBlock.model_validate(sent) + if self.status != "failed": + return None + return FailureBlock(failure_reason=self.error_code or "", hint=self.hint) + + @property + def more_claims(self) -> list[str]: + """Other claims found in the input that were not assessed.""" + sent = _sent(self, "more_claims") + return list(sent) if isinstance(sent, list) else list(self.identified_claims) #: The ``AssessResponse.status`` values this release knows about. A -#: documentation constant, like ``ExtractStatus``: the field stays ``str``. +#: documentation constant, like ``ExtractStatus``: the attribute is a ``str``. #: #: - ``ok`` — at least one row has a verdict (a list may mix in failed rows). #: - ``no_checkable_claim`` — the input, or every item, holds nothing that @@ -854,32 +744,23 @@ class AssessResponse(_Lax): found in the input — up to 20, at 1 credit each. A text that makes more claims than one call checks gets its most check-worthy 20 checked and the rest listed in ``more_claims``, unchecked and free: send them back with - ``assess(claims=...)``, 20 a call, to check them. When the input holds no - checkable claim, ``claims`` is empty, ``status`` is - ``"no_checkable_claim"`` and ``failure`` says why. + ``assess(claims=...)``, 20 a call, to check them. ``error`` is set when + the input holds no checkable claim. List form (``assess(claims=[...])``): exactly one entry per item sent, - in the order sent. An item that could not be given a verdict is a - ``"failed"`` row in position (see ``AssessClaim``), never a missing one; - the top-level ``failure`` stays ``None``. - - ``status`` (see ``AssessStatus``) sums the call up: ``ok``, - ``no_checkable_claim`` or ``error``. Computed from the rows when a server - does not send it. - - Deprecated, kept with their original meaning: ``error`` is the sentence - (``failure.detail``) and ``error_code`` is ``'no_claim'`` when the - single form found no checkable claim; both are empty otherwise. + in the order sent. An item that could not be given a verdict is an + ``"Error"`` row in position (see ``AssessClaim``), never a missing one; + the top-level ``error`` stays ``None``. + + When ``claims`` is empty (single form), ``error_code`` is ``'no_claim'``: + the input holds no checkable claim (a vague input is assessed on its + most likely reading instead). It defaults empty, so older servers that + don't send it degrade to the plain ``error`` message. """ - status: str = "" claims: list[AssessClaim] = Field(default_factory=list) - #: Why the single form has no rows; ``None`` otherwise. - failure: FailureBlock | None = None - #: Deprecated: ``failure.detail``. - error: str | None = Field(default=None, json_schema_extra={"deprecated": True}) - #: Deprecated: ``'no_claim'`` when ``failure`` says nothing was checkable. - error_code: str = Field(default="", json_schema_extra={"deprecated": True}) # '' | 'no_claim' + error: str | None = None + error_code: str = "" # '' | 'no_claim' # Deprecated: always empty since 2026-09-12. Kept because the server # still sends the key. candidate_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) @@ -889,63 +770,64 @@ class AssessResponse(_Lax): @model_validator(mode="before") @classmethod - @_reads_both("status", "failure") - def _read_both_shapes(cls, data: Any) -> Any: - if not isinstance(data, dict): + def _read_newer_shape(cls, data: Any) -> Any: + if not _is_newer(data, "failure", "error"): return data - out = dict(data) - failure = out.get("failure") - if isinstance(failure, dict): - code = failure.get("code", failure.get("failure_reason")) - out.setdefault("error", failure.get("detail")) - out.setdefault("error_code", _old_code(code, "no_claim") or "") - elif failure is None and "failure" not in data and (out.get("error") or out.get("error_code")): - out["failure"] = {"code": _new_code(out.get("error_code") or ""), "detail": out.get("error")} - if out.get("error_code") is None: - out["error_code"] = "" - if not out.get("status"): - out["status"] = _assess_status(out) - return out - - -def _assess_status(body: dict[str, Any]) -> str: - """``AssessResponse.status`` for a body that does not carry it.""" - rows = [r for r in body.get("claims") or [] if isinstance(r, dict)] - failed = [r for r in rows if r.get("status") == "failed" or r.get("verdict") in ("Error", None, "")] - if rows and len(failed) < len(rows): - return "ok" - - def _code(block: Any, fallback: Any) -> Any: - if isinstance(block, dict): - return block.get("code", block.get("failure_reason")) - return fallback + failure = data.get("failure") if isinstance(data.get("failure"), dict) else None + if failure is None: + return data + return _fill( + data, + error=failure.get("detail"), + error_code=_old_code(failure.get("code"), "no_claim") or "", + ) - if not rows: - code = _code(body.get("failure"), body.get("error_code")) - return NO_CHECKABLE_CLAIM if _new_code(code) == NO_CHECKABLE_CLAIM else "error" - codes = {_new_code(_code(r.get("failure"), r.get("error_code"))) for r in rows} - return NO_CHECKABLE_CLAIM if codes == {NO_CHECKABLE_CLAIM} else "error" + @property + def status(self) -> str: + """``ok`` (some row has a verdict), ``no_checkable_claim`` (the input, + or every item, holds nothing checkable) or ``error``. See + ``AssessStatus``; computed from the rows when a server does not send it.""" + sent = _sent(self, "status") + if isinstance(sent, str): + return sent + rows = self.claims + if any(r.status == "completed" for r in rows): + return "ok" + if not rows: + return NO_CHECKABLE_CLAIM if _new_code(self.error_code) == NO_CHECKABLE_CLAIM else "error" + codes = {r.failure.code if r.failure else None for r in rows} + return NO_CHECKABLE_CLAIM if codes == {NO_CHECKABLE_CLAIM} else "error" + + @property + def failure(self) -> FailureBlock | None: + """Why the single form has no rows; ``None`` otherwise.""" + sent = _sent(self, "failure") + if isinstance(sent, dict): + return FailureBlock.model_validate(sent) + if not (self.error or self.error_code): + return None + return FailureBlock.model_validate({"failure_reason": self.error_code, "detail": self.error}) class TaskAccepted(_Lax): - """Returned by ``POST /verify`` and per item of ``POST /verify/batch`` - and ``POST /verify/{task_id}/select``. - - ``claim`` is the item's claim on a batch or select receipt (``""`` on a - single ``verify`` receipt). ``claim_text`` is its older name, the same - string (deprecated; either response shape fills both). - """ + """Returned by ``POST /verify`` and per item of ``POST /verify/batch``.""" task_id: str = "" - claim: str = "" - #: Deprecated: the same string as :attr:`claim`. - claim_text: str = Field(default="", json_schema_extra={"deprecated": True}) + claim_text: str = "" @model_validator(mode="before") @classmethod - @_reads_both("claim") - def _read_both_shapes(cls, data: Any) -> Any: - return _mirror(data, "claim", "claim_text") if isinstance(data, dict) else data + def _read_newer_shape(cls, data: Any) -> Any: + if _is_newer(data, "claim", "claim_text"): + return _fill(data, claim_text=data["claim"]) + return data + + @property + def claim(self) -> str: + """The item's claim on a batch or select receipt (``""`` on a single + ``verify`` receipt); ``claim_text`` is its older name.""" + sent = _sent(self, "claim") + return sent if isinstance(sent, str) else self.claim_text class BatchAccepted(_Lax): @@ -1035,27 +917,18 @@ class TaskStatus(_Lax): claims: list[CandidateClaim] = Field(default_factory=list) # Deprecated, both always empty: the API no longer sends them, and # ``reason`` is only ever ``multi_claim``. Kept so code that reads them - # keeps working; removal is planned for 2026-11-29. Marked deprecated in + # keeps working; they are deprecated and kept. Marked deprecated in # the JSON schema only, so reading them does not warn. candidates: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) similar_claims: list[SimilarVerification] = Field(default_factory=list, json_schema_extra={"deprecated": True}) - #: On ``failed``: why. ``failure.code`` is the specific cause (an open - #: set, e.g. ``research_empty``, ``no_checkable_claim``), ``failure.detail`` - #: one sentence on what happened, ``failure.failure_class`` the closed - #: :data:`FailureClass`, ``failure.retryable`` whether resending the same - #: claim can help, ``failure.hint`` what to send instead (when the server - #: has one) and ``failure.docs_url`` where the class is explained. Filled - #: from either response shape; ``None`` on every other status. - failure: FailureBlock | None = None - # The original failure fields, deprecated and kept with their original - # meaning whichever response shape arrived: ``error`` is the sentence, - # ``failure_reason`` the cause (``not_a_claim`` where ``failure.code`` - # reads ``no_checkable_claim``), and ``failure_class`` / ``retryable`` / - # ``docs_url`` / ``hint`` the same values as on ``failure``. - # ``failure_detail`` is never sent by the API; it stays for old code. - error: str = Field(default="", json_schema_extra={"deprecated": True}) - failure_reason: str = Field(default="", json_schema_extra={"deprecated": True}) - failure_detail: str = Field(default="", json_schema_extra={"deprecated": True}) + # failure branches. The server's failed response is + # ``{"status": "failed", "error": "..."}`` — ``error`` is the live wire + # field. ``failure_reason`` / ``failure_detail`` are kept for forward/back + # compatibility and other channels; read precedence is + # ``error or failure_detail or failure_reason``. + error: str = "" + failure_reason: str = "" + failure_detail: str = "" # WHY it failed — the closed set is ``FailureClass`` (import it for # exhaustive matching). The annotation stays ``str`` on purpose: a # ``Literal`` here would make an unknown class the server adds later a @@ -1069,40 +942,42 @@ class TaskStatus(_Lax): @model_validator(mode="before") @classmethod - @_reads_both("failure") - def _read_both_shapes(cls, data: Any) -> Any: - if not isinstance(data, dict): + def _read_newer_shape(cls, data: Any) -> Any: + if not _is_newer(data, "failure", "failure_reason") or not isinstance(data["failure"], dict): return data - out = dict(data) - failure = out.get("failure") - if isinstance(failure, dict): - # The newer shape: the original top-level fields from the block. - code = failure.get("code", failure.get("failure_reason")) - for key, value in ( - ("error", failure.get("detail")), - ("failure_reason", _old_code(code, "not_a_claim")), - ("failure_class", failure.get("failure_class")), - ("retryable", failure.get("retryable")), - ("docs_url", failure.get("docs_url")), - ("hint", failure.get("hint")), - ): - if out.get(key) is None: - out[key] = value - elif out.get("status") == "failed" and failure is None: - # The original shape: the block from the top-level fields. - out["failure"] = { - "code": _new_code(out.get("failure_reason") or ""), - "detail": out.get("error") or out.get("failure_detail") or None, - "failure_class": out.get("failure_class") or "", - "retryable": out.get("retryable") if isinstance(out.get("retryable"), bool) else None, - "hint": out.get("hint") or None, - "docs_url": out.get("docs_url") or "", + failure = data["failure"] + values = { + "error": failure.get("detail"), + "failure_reason": _old_code(failure.get("code"), "not_a_claim"), + "failure_class": failure.get("failure_class"), + "retryable": failure.get("retryable"), + "docs_url": failure.get("docs_url"), + "hint": failure.get("hint"), + } + # ``None`` reads as the original field's empty value. + return _fill(data, **{k: ("" if v is None and k != "retryable" else v) for k, v in values.items()}) + + @property + def failure(self) -> FailureBlock | None: + """On ``failed``: why. ``code`` is the cause (an open set, e.g. + ``research_empty``, ``no_checkable_claim``), ``detail`` one sentence on + what happened, ``failure_class`` / ``retryable`` / ``hint`` / + ``docs_url`` as on the original fields. ``None`` on other statuses.""" + sent = _sent(self, "failure") + if isinstance(sent, dict): + return FailureBlock.model_validate(sent) + if self.status != "failed": + return None + return FailureBlock.model_validate( + { + "failure_reason": self.failure_reason, + "detail": self.error or self.failure_detail or None, + "failure_class": self.failure_class, + "retryable": self.retryable, + "hint": self.hint or None, + "docs_url": self.docs_url, } - # ``None`` reads as the field's empty value, never as a validation error. - for key in ("error", "failure_reason", "failure_detail", "failure_class", "docs_url", "hint", "reason"): - if key in out and out[key] is None: - out[key] = "" - return out + ) class BatchItemResult(_Lax): @@ -1122,18 +997,15 @@ class BatchItemResult(_Lax): """ task_id: str = "" - claim: str = "" - #: Deprecated: the same string as :attr:`claim`. - claim_text: str = Field(default="", json_schema_extra={"deprecated": True}) + claim_text: str = "" status: Literal["completed", "needs_input", "failed", "timeout"] verification: Verification | None = None status_detail: TaskStatus | None = None - @model_validator(mode="before") - @classmethod - @_reads_both("claim") - def _read_both_names(cls, data: Any) -> Any: - return _mirror(data, "claim", "claim_text") if isinstance(data, dict) else data + @property + def claim(self) -> str: + """The item's claim (``claim_text`` is its older name).""" + return self.claim_text class UsageCredits(_Lax): @@ -1161,8 +1033,7 @@ class UsageCredits(_Lax): extra: int = 0 #: **Deprecated** old name of :attr:`extra`, the same number, kept for #: existing code. Reading it emits a ``DeprecationWarning``; it stays in - #: ``model_dump()`` output (unwarned), filled from ``extra`` when the - #: server does not send it. + #: ``model_dump()`` output (unwarned) for as long as the server sends it. bonus: int = Field( default=0, deprecated=( @@ -1177,8 +1048,8 @@ def _mirror_extra_and_bonus(cls, data: Any) -> Any: """Keep ``extra`` and its deprecated old name in step, in both directions. A server that has not started sending ``extra`` sends only ``bonus``; - the newer response shape sends only ``extra``. Mirroring here means - both attributes read correctly either way. + the newer response shape sends only ``extra``. Mirroring + here means both attributes read correctly either way. """ if not isinstance(data, dict): return data @@ -1194,10 +1065,9 @@ class UsageCapacity(_Lax): """DEPRECATED. One capability's share of the pool, in that capability's unit. Deprecated, together with the per-block ``credits`` alias, and kept for - existing code: the newer response shape does not send these blocks, and - the SDK then computes them from :attr:`Usage.credits` and - :attr:`Usage.costs`. Read those two and do the division yourself — it is - the same one this block does:: + existing code (computed from the pool when a response leaves the block + out). Read :attr:`Usage.credits` and :attr:`Usage.costs` and do the division — + it is the same one this block does:: remaining = u.credits.remaining // u.costs[capability] total = u.credits.total // u.costs[capability] @@ -1250,8 +1120,8 @@ class UsageCapacity(_Lax): def _mirror_bonus_and_credits(cls, data: Any) -> Any: """Keep ``bonus`` and its deprecated alias in step, in both directions. - A server predating the credit pool sends only ``credits``; a block the - SDK computed has only ``bonus``. Mirroring here means + A server predating the credit pool sends only ``credits``; a block + computed from the pool has only ``bonus``. Mirroring here means both attributes read correctly either way, so the SDK never depends on which side of an API deploy it is talking to. """ @@ -1302,9 +1172,7 @@ class Usage(_Lax): #: comparing against it will break on a rename that ought to be free. #: Empty on servers predating this field — fall back to :attr:`plan`. plan_label: str = "" - #: Deprecated: the same time as ``credits.resets_at``, which it is - #: filled from when the server does not send it. - quota_resets_at: str | None = Field(default=None, json_schema_extra={"deprecated": True}) + quota_resets_at: str | None = None #: The credit balance — the authoritative number. Empty on older servers. credits: UsageCredits = Field(default_factory=UsageCredits) #: Credits per call, keyed by CAPABILITY, at its default price: @@ -1344,9 +1212,6 @@ class Usage(_Lax): #: :attr:`costs` instead:: #: #: left = u.credits.remaining // u.costs["verify"] - #: - #: Computed that way when the server does not send the block (the newer - #: response shape does not). verify: UsageCapacity = Field(default_factory=UsageCapacity) #: DEPRECATED, kept for existing code. See :attr:`verify`. ask: UsageCapacity = Field(default_factory=UsageCapacity) @@ -1362,45 +1227,35 @@ class Usage(_Lax): @model_validator(mode="before") @classmethod - @_reads_both(always_hide=True) - def _read_both_shapes(cls, data: Any) -> Any: - """Compute the deprecated blocks the newer response shape leaves out. - - Each per-capability block is the credit pool divided by that - capability's price, exactly as the server computed it; it is filled - only when the server sent the pool and the price but not the block. - """ - if not isinstance(data, dict): + def _read_newer_shape(cls, data: Any) -> Any: + """The newer shape sends the pool and the prices but not the + deprecated per-capability blocks: compute them exactly as the server + did, and ``quota_resets_at`` from ``credits.resets_at``.""" + if not (isinstance(data, dict) and isinstance(data.get("credits"), dict)): return data - credits, costs = data.get("credits"), data.get("costs") - if not isinstance(credits, dict): + if any(k in data for k in ("verify", "ask", "assess", "quota_resets_at")): return data - out = dict(data) - if "quota_resets_at" not in out: - out["quota_resets_at"] = credits.get("resets_at") - if not isinstance(costs, dict): - return out + credits, costs = data["credits"], data.get("costs") def _int(value: Any) -> int: return value if isinstance(value, int) and not isinstance(value, bool) else 0 - total, remaining, extra = ( - _int(credits.get("total")), - _int(credits.get("remaining")), - _int(credits.get("extra", credits.get("bonus"))), - ) + out = _fill(data, quota_resets_at=credits.get("resets_at")) + if not isinstance(costs, dict): + return out + total, remaining = _int(credits.get("total")), _int(credits.get("remaining")) + extra = _int(credits.get("extra", credits.get("bonus"))) for capability in ("verify", "ask", "assess"): cost = _int(costs.get(capability)) - if capability in out or cost <= 0: - continue - quota_total, left = total // cost, remaining // cost - out[capability] = { - "quota_used": quota_total - left, - "quota_total": quota_total, - "quota_remaining": left, - "bonus": extra // cost, - "remaining": left, - } + if cost > 0: + quota_total, left = total // cost, remaining // cost + out[capability] = { + "quota_used": quota_total - left, + "quota_total": quota_total, + "quota_remaining": left, + "bonus": extra // cost, + "remaining": left, + } return out @@ -1470,6 +1325,45 @@ class ReviewStarted(_Lax): status: str = "queued" +class FailureBlock(_Lax): + """Why a review, or one claim's work inside it, failed. + + The same fields a failed ``GET /verify/status`` carries: ``failure_reason`` + is the specific cause (an open set, e.g. ``no_claim``, + ``insufficient_credits``, ``timeout``), ``failure_class`` the closed + :data:`FailureClass`, ``retryable`` whether resending the same request can + help, ``hint`` one sentence on what to do next and ``docs_url`` where the + class is explained. + """ + + failure_reason: str | None = "" + failure_class: str | None = "" + retryable: bool | None = None + hint: str | None = None + docs_url: str | None = "" + + @model_validator(mode="before") + @classmethod + def _read_newer_shape(cls, data: Any) -> Any: + if _is_newer(data, "code", "failure_reason"): + return _fill(data, failure_reason=_old_code(data["code"], "no_claim")) + return data + + @property + def code(self) -> str | None: + """The cause, an open set (``no_checkable_claim``, ``timeout``, ...). + ``failure_reason`` is its older name, spelling "nothing checkable" + ``no_claim``.""" + sent = _sent(self, "code") + return sent if isinstance(sent, str) else _new_code(self.failure_reason) + + @property + def detail(self) -> str | None: + """One sentence on what happened; ``None`` from the original shape.""" + sent = _sent(self, "detail") + return sent if isinstance(sent, str) else None + + class EscalationPolicy(_Lax): """Which quick-checked claims get a deep check, as the review RESOLVED it. @@ -1537,19 +1431,11 @@ class ReviewSummary(_Lax): The ``citation*`` counts are ``None`` (``citation_issues`` 0) on a review that did not ask for the citation check.""" - #: How many claims the draft holds. ``None`` until the draft is read, - #: and from the original response shape, which does not send it. - claims_found: int | None = None claims_selected: int | None = None #: The resolved ``max_assessments``. claim_limit: int = 20 - #: Some of the draft's claims were left out (more than ``claim_limit``): - #: they are in ``more_claims``. From the original response shape it is - #: read off ``more_claims`` once the draft is read. - claim_limit_exceeded: bool | None = None - #: Deprecated: the draft held at least ``claim_limit`` claims, so more - #: MAY exist. Read :attr:`claim_limit_exceeded`, which says whether they do. - claim_limit_reached: bool | None = Field(default=None, json_schema_extra={"deprecated": True}) + #: The draft held at least ``claim_limit`` claims: more MAY exist. + claim_limit_reached: bool | None = None #: The text was cut at 50,000 characters. input_truncated: bool = False assessments: ReviewAssessmentCounts | None = None @@ -1561,10 +1447,8 @@ class ReviewSummary(_Lax): citations_selected: int | None = None #: The resolved ``max_citations``. citation_limit: int | None = None - #: ``citations_found`` is over ``citation_limit``: some were left out. - citation_limit_exceeded: bool | None = None - #: Deprecated: the same value as :attr:`citation_limit_exceeded`. - citation_limit_reached: bool | None = Field(default=None, json_schema_extra={"deprecated": True}) + #: ``citations_found`` is over ``citation_limit``. + citation_limit_reached: bool | None = None citation_checks: ReviewCitationCheckCounts | None = None #: ``len(citation_issues)``. citation_issues: int = 0 @@ -1575,15 +1459,33 @@ class ReviewSummary(_Lax): @model_validator(mode="before") @classmethod - @_reads_both("claims_found", "claim_limit_exceeded", "citation_limit_exceeded") - def _read_both_shapes(cls, data: Any) -> Any: - if not isinstance(data, dict): + def _read_newer_shape(cls, data: Any) -> Any: + if not _is_newer(data, "claim_limit_exceeded", "claim_limit_reached"): return data - out = _mirror(dict(data), "citation_limit_exceeded", "citation_limit_reached") - if "claim_limit_reached" not in out and "claims_found" in out: - found, limit = out.get("claims_found"), out.get("claim_limit", 20) - out["claim_limit_reached"] = found >= limit if isinstance(found, int) and isinstance(limit, int) else None - return out + found, limit = data.get("claims_found"), data.get("claim_limit", 20) + reached = found >= limit if isinstance(found, int) and isinstance(limit, int) else None + return _fill(data, claim_limit_reached=reached, citation_limit_reached=data.get("citation_limit_exceeded")) + + @property + def claims_found(self) -> int | None: + """How many claims the draft holds; ``None`` until read, and from the + original response shape, which does not send it.""" + sent = _sent(self, "claims_found") + return sent if isinstance(sent, int) else None + + @property + def claim_limit_exceeded(self) -> bool | None: + """Some of the draft's claims were left out (they are in + ``more_claims``). ``None`` from the original response shape, which + says only that the limit was reached: read ``more_claims`` there.""" + sent = _sent(self, "claim_limit_exceeded") + return sent if isinstance(sent, bool) else None + + @property + def citation_limit_exceeded(self) -> bool | None: + """``citations_found`` is over ``citation_limit``: some were left out.""" + sent = _sent(self, "citation_limit_exceeded") + return sent if isinstance(sent, bool) else self.citation_limit_reached class ReviewCredits(_Lax): @@ -1608,15 +1510,8 @@ class ReviewResult(_Lax): class ReviewAssessment(_Lax): """A claim's quick check. ``status``: ``pending`` | ``running`` | ``completed`` | ``failed``. On ``completed`` the fields mean what they - mean on an ``/assess`` row; on ``failed`` see ``failure`` (its ``code`` - an open set, as on ``/assess``). ``more_claims`` lists other claims - found in the passage that were not checked. - - Deprecated, kept with their original meaning: ``error_code`` is - ``failure.code`` on a failed row (``no_claim`` where the code reads - ``no_checkable_claim``), ``identified_claims`` is ``more_claims``, and - ``hint`` is the row's own hint from the original response shape - (``None`` from the newer one; read ``failure.hint``).""" + mean on an ``/assess`` row; on ``failed`` see ``error_code`` (an open + set, as on ``/assess``), ``hint`` and ``failure``.""" status: str = "" verdict: str | None = None @@ -1624,13 +1519,9 @@ class ReviewAssessment(_Lax): rationale: str | None = None dissent: str | None = None verification_url: str | None = None - more_claims: list[str] = Field(default_factory=list) - #: Deprecated: ``failure.code`` on a failed row. - error_code: str | None = Field(default=None, json_schema_extra={"deprecated": True}) - #: Deprecated: :attr:`more_claims`. - identified_claims: list[str] = Field(default_factory=list, json_schema_extra={"deprecated": True}) - #: Deprecated. See the class docstring. - hint: str | None = Field(default=None, json_schema_extra={"deprecated": True}) + error_code: str | None = None + identified_claims: list[str] = Field(default_factory=list) + hint: str | None = None #: With ``suggest_edits=True``: the claim with its wrong part corrected, #: from the quick check's reasoning, when it found the claim "False" or #: "Mostly False" with high confidence. ``None`` otherwise, and from @@ -1641,15 +1532,21 @@ class ReviewAssessment(_Lax): @model_validator(mode="before") @classmethod - @_reads_both("more_claims") - def _read_both_shapes(cls, data: Any) -> Any: - if not isinstance(data, dict): + def _read_newer_shape(cls, data: Any) -> Any: + if not _is_newer(data, "more_claims", "identified_claims"): return data - out = _mirror(dict(data), "more_claims", "identified_claims") - failure = out.get("failure") - if "error_code" not in out and isinstance(failure, dict): - out["error_code"] = _old_code(failure.get("code", failure.get("failure_reason")), "no_claim") - return out + failure = data.get("failure") if isinstance(data.get("failure"), dict) else {} + return _fill( + data, + identified_claims=data.get("more_claims") or [], + error_code=_old_code(failure.get("code"), "no_claim") if failure else None, + ) + + @property + def more_claims(self) -> list[str]: + """Other claims found in the passage that were not checked.""" + sent = _sent(self, "more_claims") + return list(sent) if isinstance(sent, list) else list(self.identified_claims) class ReviewEntity(_Lax): @@ -1691,19 +1588,23 @@ class ReviewVerification(_Lax): suggested_rewrite: str | None = None warnings: list[str] = Field(default_factory=list) created_at: str | None = None - #: See ``Verification.completed_at``. - completed_at: str | None = None - #: Deprecated. See ``Verification.modified_at``. - modified_at: str | None = Field(default=None, json_schema_extra={"deprecated": True}) + modified_at: str | None = None verification_url: str | None = None url: str | None = None failure: FailureBlock | None = None @model_validator(mode="before") @classmethod - @_reads_both("completed_at") - def _read_both_shapes(cls, data: Any) -> Any: - return _with_completion_times(data) + def _read_newer_shape(cls, data: Any) -> Any: + return _fill_modified_at(data) + + @property + def completed_at(self) -> str | None: + """When the verification completed. From the original response shape it + is known only through ``modified_at``: set when that is, ``None`` on a + same-day completion.""" + sent = _sent(self, "completed_at") + return sent if isinstance(sent, str) else self.modified_at class SuggestedEdit(_Lax): @@ -2005,18 +1906,22 @@ class CitecheckSummary(_Lax): citations_found: int | None = None citations_selected: int | None = None citation_limit: int | None = None - #: ``citations_found`` is over ``citation_limit``: some were left out. - citation_limit_exceeded: bool | None = None - #: Deprecated: the same value as :attr:`citation_limit_exceeded`. - citation_limit_reached: bool | None = Field(default=None, json_schema_extra={"deprecated": True}) + citation_limit_reached: bool | None = None citation_checks: ReviewCitationCheckCounts | None = None citation_issues: int = 0 @model_validator(mode="before") @classmethod - @_reads_both("citation_limit_exceeded") - def _read_both_shapes(cls, data: Any) -> Any: - return _mirror(data, "citation_limit_exceeded", "citation_limit_reached") if isinstance(data, dict) else data + def _read_newer_shape(cls, data: Any) -> Any: + if _is_newer(data, "citation_limit_exceeded", "citation_limit_reached"): + return _fill(data, citation_limit_reached=data["citation_limit_exceeded"]) + return data + + @property + def citation_limit_exceeded(self) -> bool | None: + """``citations_found`` is over ``citation_limit``: some were left out.""" + sent = _sent(self, "citation_limit_exceeded") + return sent if isinstance(sent, bool) else self.citation_limit_reached class Citecheck(_Lax): @@ -2093,15 +1998,6 @@ class ReviewEnvelope(_Lax): more_citations: list[ReviewMoreCitation] | None = None failure: FailureBlock | None = None - @model_validator(mode="after") - def _claim_limit_exceeded_from_more_claims(self) -> ReviewEnvelope: - """The original shape says only that the limit was REACHED; whether - claims were left out is whether ``more_claims`` lists any.""" - summary = self.summary - if summary.claim_limit_exceeded is None and self.more_claims is not None: - summary.claim_limit_exceeded = bool(self.more_claims) - return self - class ReviewFull(ReviewEnvelope): """``GET /reviews/{review_id}``: the envelope plus every claim.""" diff --git a/src/lenz_io/webhooks.py b/src/lenz_io/webhooks.py index a28409b..b1141ee 100644 --- a/src/lenz_io/webhooks.py +++ b/src/lenz_io/webhooks.py @@ -34,15 +34,16 @@ from datetime import datetime, timezone from typing import Any +from pydantic import ValidationError + from .errors import LenzWebhookSignatureError from .models import ( CandidateClaim, Citecheck, FailureBlock, ReviewFull, - _new_code, + _fill_modified_at, _old_code, - _with_completion_times, ) SIGNATURE_HEADER = "X-Lenz-Signature" @@ -95,24 +96,11 @@ def verify_signature(raw_body: bytes, signature: str, secret: str) -> bool: # ── Typed events ───────────────────────────────────────────────────────── -# -# Two payload shapes reach the same events. The original one is flat for -# ``verification.*`` (``result``, ``needs_input``, ``error`` at the top) and -# nested for ``review.*`` / ``citecheck.*``. The newer one is one envelope for -# every event: ``event``, ``event_id``, the work's id, ``status``, and the body -# polling returns under the work's kind (``verification``, ``review``, -# ``citecheck``). Every attribute below is filled from either shape, and the -# original attributes keep their original meaning. @dataclass class WebhookEvent: - """Base class. Use ``isinstance`` to discriminate the union. - - ``event_id`` is the same on every delivery attempt of one event, while - ``attempt`` counts up: deduplicate on it. ``""`` when a payload does not - carry it (the original ``verification.*`` and ``certificate.*`` shape). - """ + """Base class. Use ``isinstance`` to discriminate the union.""" event: str task_id: str @@ -122,18 +110,19 @@ class WebhookEvent: batch_id: str | None = None status: str = "" raw: dict[str, Any] = field(default_factory=dict, repr=False) - # Keyword-only, so positional construction of every event keeps its order. - event_id: str = field(default="", kw_only=True) + + @property + def event_id(self) -> str: + """The same on every delivery attempt of one event: deduplicate on it. + ``""`` when the payload carries none (the original ``verification.*`` + and ``certificate.*`` payloads).""" + value = self.raw.get("event_id") + return value if isinstance(value, str) else "" @dataclass class VerificationCompleted(WebhookEvent): - """``event=verification.completed`` — the pipeline produced a verdict. - - ``result`` is the verification as a dict, the same body - ``verifications.get`` returns, as sent; from the newer payload shape, - which sends ``completed_at``, the deprecated ``modified_at`` is added. - """ + """``event=verification.completed`` — the pipeline produced a verdict.""" result: dict[str, Any] = field(default_factory=dict) @@ -142,22 +131,33 @@ class VerificationCompleted(WebhookEvent): class VerificationFailed(WebhookEvent): """``event=verification.failed`` — the pipeline terminated without a verdict. - ``failure`` says why: ``failure.code`` is the cause (an open set), - ``failure.detail`` one sentence on what happened, ``failure.failure_class`` - the closed set (``upstream_unavailable`` | ``insufficient_evidence`` | - ``invalid_input`` | ``cancelled`` | ``internal``) and ``failure.retryable`` - the derived signal (true iff ``upstream_unavailable``). - - The original attributes keep their meaning: ``error`` is the cause code - (``not_a_claim`` where ``failure.code`` reads ``no_checkable_claim``), - and ``failure_class`` / ``retryable`` repeat the block's. They default when - an older server omits them. + ``failure_class`` is WHY (closed set — ``upstream_unavailable`` | + ``insufficient_evidence`` | ``invalid_input`` | ``cancelled`` | + ``internal``); ``retryable`` is the derived signal (true iff + ``upstream_unavailable``). Both default when an older server omits them. """ error: str = "" failure_class: str = "" retryable: bool | None = None - failure: FailureBlock | None = None + + @property + def failure(self) -> FailureBlock | None: + """Why the run failed, from either payload shape: ``code`` (the cause, + ``no_checkable_claim`` where ``error`` reads ``not_a_claim``), + ``detail`` (one sentence, newer payloads only), ``failure_class``, + ``retryable``, ``hint`` and ``docs_url``. ``None`` when the payload + names no cause.""" + body = self.raw.get("verification") + block = body.get("failure") if isinstance(body, dict) else None + if not isinstance(block, dict): + if not (self.error or self.failure_class): + return None + block = {"failure_reason": self.error, "failure_class": self.failure_class, "retryable": self.retryable} + try: + return FailureBlock.model_validate(block) + except ValidationError: + return None @dataclass @@ -168,18 +168,34 @@ class VerificationNeedsInput(WebhookEvent): pipeline run produces a ``verification.completed`` (or another ``needs_input``) event. - ``reason`` is why (``multi_claim``), ``claims`` the options to pick from - (each with ``claim`` and ``domain``) and ``hint`` one sentence on what was - unclear and how to resolve it (``""`` when an older server omits it). - ``needs_input`` is the original dict, ``{"reason", "claims", "hint"}``, - whose options carry the claim as ``text``: as sent, or built from the - newer payload shape. + ``hint`` is one sentence on what was unclear and how to resolve it + (``needs_input["hint"]`` on the wire); ``""`` when an older server omits + it. """ needs_input: dict[str, Any] = field(default_factory=dict) hint: str = "" - reason: str = "" - claims: list[CandidateClaim] = field(default_factory=list) + + @property + def reason(self) -> str: + """Why the run paused (``multi_claim``).""" + value = self.needs_input.get("reason") if isinstance(self.needs_input, dict) else None + return value if isinstance(value, str) else "" + + @property + def claims(self) -> list[CandidateClaim]: + """The options to pick from, each with ``claim`` and ``domain``. An + option that cannot be read is left out, never raised on.""" + options = self.needs_input.get("claims") if isinstance(self.needs_input, dict) else None + out = [] + for option in options or []: + if not isinstance(option, dict): + continue + try: + out.append(CandidateClaim.model_validate({k: v for k, v in option.items() if v is not None})) + except ValidationError: + continue + return out @dataclass @@ -211,10 +227,10 @@ class ReviewEvent(WebhookEvent): ``review.issues``. Deduplicate on ``event_id``: it is the same on every delivery attempt of - one event, while ``attempt`` counts up. ``task_id`` (deprecated) - identifies the delivery and cannot be polled on ``/verify/status``; it is - ``""`` on a payload that does not carry it (the newer shape). The deep - checks a review runs send no ``verification.*`` events of their own. + one event, while ``attempt`` counts up. ``task_id`` identifies the + delivery and cannot be polled on ``/verify/status``; the newer payload + shape leaves it out (it reads ``""``). The deep checks a + review runs send no ``verification.*`` events of their own. """ event_id: str = "" @@ -230,9 +246,9 @@ class CitecheckEvent(WebhookEvent): ``citecheck`` is the final check (the same body ``get_citecheck`` returns), or ``None`` if it could not be parsed (``raw["citecheck"]`` still has it). Deduplicate on ``event_id``: it is the same on every - delivery attempt of one event. ``task_id`` (deprecated) identifies the - delivery and cannot be polled on ``/verify/status``; it is ``""`` on a - payload that does not carry it (the newer shape). + delivery attempt of one event. ``task_id`` identifies the delivery and + cannot be polled on ``/verify/status``; the newer payload shape leaves it + out (it reads ``""``). """ event_id: str = "" @@ -240,125 +256,152 @@ class CitecheckEvent(WebhookEvent): citecheck: Citecheck | None = None -def _dict(value: Any) -> dict[str, Any]: - return value if isinstance(value, dict) else {} - - -def _opt_id(*values: Any) -> str | None: - for value in values: - if value: - return str(value) - return None - - -def _legacy_needs_input(payload: dict[str, Any], body: dict[str, Any]) -> dict[str, Any]: - """The original ``needs_input`` dict: as sent, or built from the newer - envelope's polled body (each option carrying the claim as ``text``).""" - if isinstance(payload.get("needs_input"), dict): - return payload["needs_input"] # type: ignore[no-any-return] - claims = [] - for option in body.get("claims") or []: - if isinstance(option, dict): - claims.append({"text": option.get("claim", option.get("text")), "domain": option.get("domain", "")}) - out: dict[str, Any] = {"reason": body.get("reason", "")} - out["claims"] = claims - out["hint"] = body.get("hint", "") - return out +def _original_view(payload: dict[str, Any]) -> dict[str, Any]: + """The original flat ``verification.*`` fields, for a payload in the newer + envelope (the polled body nested under ``verification``). Any other + payload is returned as it is.""" + body = payload.get("verification") + if not isinstance(body, dict): + return payload + view = dict(payload) + view.setdefault("task_id", body.get("task_id")) + result = body.get("result") + if isinstance(result, dict): + view.setdefault("result", _fill_modified_at(result)) + view.setdefault("verification_id", result.get("verification_id")) + failure = body.get("failure") + if isinstance(failure, dict): + view.setdefault("error", _old_code(failure.get("code"), "not_a_claim")) + view.setdefault("failure_class", failure.get("failure_class")) + view.setdefault("retryable", failure.get("retryable")) + if body.get("status") == "needs_input": + options = [ + {"text": o.get("claim", o.get("text")), "domain": o.get("domain", "")} + for o in body.get("claims") or [] + if isinstance(o, dict) + ] + view.setdefault( + "needs_input", {"reason": body.get("reason", ""), "claims": options, "hint": body.get("hint", "")} + ) + view.setdefault("coverage", body.get("coverage") or (result or {}).get("coverage")) + return view -def _build_event(payload: dict[str, Any]) -> WebhookEvent: +def _build_event(raw: dict[str, Any]) -> WebhookEvent: """Discriminate on ``event`` and return the right typed dataclass.""" + payload = _original_view(raw) event = str(payload.get("event") or "") - # The newer envelope nests the polled body under the work's kind. - body = _dict(payload.get("verification")) - result = _dict(payload.get("result")) or _dict(body.get("result")) - event_id = str(payload.get("event_id") or "") - task_id = str(payload.get("task_id") or body.get("task_id") or "") + task_id = str(payload.get("task_id") or "") try: attempt = int(payload.get("attempt") or 1) except (TypeError, ValueError): attempt = 1 delivered_at = str(payload.get("delivered_at") or "") - verification_id = _opt_id(payload.get("verification_id"), result.get("verification_id")) - batch_id = _opt_id(payload.get("batch_id"), body.get("batch_id")) - status = str(payload.get("status") or body.get("status") or "") - common: dict[str, Any] = { - "event": event, - "task_id": task_id, - "attempt": attempt, - "delivered_at": delivered_at, - "verification_id": verification_id, - "batch_id": batch_id, - "status": status, - "raw": payload, - "event_id": event_id, - } + verification_id = str(payload["verification_id"]) if payload.get("verification_id") else None + batch_id = str(payload["batch_id"]) if payload.get("batch_id") else None + status = str(payload.get("status") or "") if event == "verification.completed": - if result and "modified_at" not in result: - # The newer shape: add the original ``modified_at`` (computed), - # leaving an original-shape result exactly as sent. - result = _with_completion_times(result) - return VerificationCompleted(**common, result=result) + return VerificationCompleted( + event=event, + task_id=task_id, + attempt=attempt, + delivered_at=delivered_at, + verification_id=verification_id, + batch_id=batch_id, + status=status, + raw=raw, + result=payload.get("result") or {}, + ) if event == "verification.failed": - block = _dict(body.get("failure")) or _dict(payload.get("failure")) - failure = FailureBlock.model_validate(block) if block else None - legacy_error = payload.get("error") - error = legacy_error if isinstance(legacy_error, str) and legacy_error else "" - if not error and failure is not None: - error = str(_old_code(failure.code, "not_a_claim") or "") - failure_class = payload.get("failure_class") or (failure.failure_class if failure else "") or "" - retryable = payload.get("retryable") - if not isinstance(retryable, bool): - retryable = failure.retryable if failure is not None else None - if failure is None and (error or failure_class): - # The original shape: the block from the flat fields. - failure = FailureBlock.model_validate( - {"code": _new_code(error), "failure_class": failure_class, "retryable": retryable} - ) return VerificationFailed( - **common, - error=error, - failure_class=str(failure_class), - retryable=retryable if isinstance(retryable, bool) else None, - failure=failure, + event=event, + task_id=task_id, + attempt=attempt, + delivered_at=delivered_at, + verification_id=verification_id, + batch_id=batch_id, + status=status, + raw=raw, + error=str(payload.get("error") or ""), + failure_class=str(payload.get("failure_class") or ""), + retryable=payload.get("retryable") if isinstance(payload.get("retryable"), bool) else None, ) if event == "verification.needs_input": - needs_input = _legacy_needs_input(payload, body) + needs_input = payload.get("needs_input") or {} return VerificationNeedsInput( - **common, + event=event, + task_id=task_id, + attempt=attempt, + delivered_at=delivered_at, + verification_id=verification_id, + batch_id=batch_id, + status=status, + raw=raw, needs_input=needs_input, - hint=str(needs_input.get("hint") or ""), - reason=str(needs_input.get("reason") or ""), - claims=[CandidateClaim.model_validate(c) for c in needs_input.get("claims") or [] if isinstance(c, dict)], + hint=str(needs_input.get("hint") or "") if isinstance(needs_input, dict) else "", ) if event == "certificate.timestamped": - coverage = _dict(payload.get("coverage")) or _dict(body.get("coverage")) or _dict(result.get("coverage")) - return CertificateTimestamped(**common, coverage=coverage) + return CertificateTimestamped( + event=event, + task_id=task_id, + attempt=attempt, + delivered_at=delivered_at, + verification_id=verification_id, + batch_id=batch_id, + status=status, + raw=raw, + coverage=payload.get("coverage") or {}, + ) if event in ("review.completed", "review.failed"): - review_body = payload.get("review") + body = payload.get("review") try: - review = ReviewFull.model_validate(review_body) if isinstance(review_body, dict) else None + review = ReviewFull.model_validate(body) if isinstance(body, dict) else None except ValueError: review = None return ReviewEvent( - **common, - review_id=str(payload.get("review_id") or _dict(review_body).get("review_id") or ""), + event=event, + task_id=task_id, + attempt=attempt, + delivered_at=delivered_at, + verification_id=verification_id, + batch_id=batch_id, + status=status, + raw=raw, + event_id=str(payload.get("event_id") or ""), + review_id=str(payload.get("review_id") or ""), review=review, ) if event in ("citecheck.completed", "citecheck.failed"): - check_body = payload.get("citecheck") + body = payload.get("citecheck") try: - check = Citecheck.model_validate(check_body) if isinstance(check_body, dict) else None + check = Citecheck.model_validate(body) if isinstance(body, dict) else None except ValueError: check = None return CitecheckEvent( - **common, - citecheck_id=str(payload.get("citecheck_id") or _dict(check_body).get("citecheck_id") or ""), + event=event, + task_id=task_id, + attempt=attempt, + delivered_at=delivered_at, + verification_id=verification_id, + batch_id=batch_id, + status=status, + raw=raw, + event_id=str(payload.get("event_id") or ""), + citecheck_id=str(payload.get("citecheck_id") or ""), citecheck=check, ) # Unknown event type — return generic. Future-compatible: ignore events # you do not handle rather than failing the delivery. - return WebhookEvent(**common) + return WebhookEvent( + event=event, + task_id=task_id, + attempt=attempt, + delivered_at=delivered_at, + verification_id=verification_id, + batch_id=batch_id, + status=status, + raw=raw, + ) def parse_webhook(body: bytes | str | dict[str, Any]) -> WebhookEvent: diff --git a/tests/fixtures/parity/canonical/account__api_root.json b/tests/fixtures/parity/canonical/account__api_root.json new file mode 100644 index 0000000..592cd14 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__api_root.json @@ -0,0 +1,43 @@ +{ + "status": 200, + "body": { + "name": "Lenz Public API", + "version": "v1", + "docs_url": "https://lenz.io/api/v1/docs/", + "openapi_url": "https://lenz.io/api/v1/openapi.json", + "quickstart_url": "https://lenz.io/docs/quickstart", + "developer_portal_url": "https://lenz.io/developers", + "endpoints": { + "extract": "https://lenz.io/api/v1/extract", + "assess": "https://lenz.io/api/v1/assess", + "verify": "https://lenz.io/api/v1/verify", + "ask": "https://lenz.io/api/v1/ask/{verification_id}", + "verify_status": "https://lenz.io/api/v1/verify/status/{task_id}", + "verifications": "https://lenz.io/api/v1/verifications/{verification_id}", + "library": "https://lenz.io/api/v1/library", + "usage": "https://lenz.io/api/v1/me/usage" + }, + "sdks": { + "python": { + "repository": "https://github.com/lenzhq/lenz-io-python", + "package": "https://pypi.org/project/lenz-io/", + "install": "pip install lenz-io" + }, + "node": { + "repository": "https://github.com/lenzhq/lenz-io-node", + "package": "https://www.npmjs.com/package/lenz-io", + "install": "npm install lenz-io" + } + }, + "mcp": { + "url": "https://lenz.io/mcp", + "transport": "streamable-http", + "repository": "https://github.com/lenzhq/lenz-mcp" + } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__ask_history_after_reset.json b/tests/fixtures/parity/canonical/account__ask_history_after_reset.json new file mode 100644 index 0000000..e9962b2 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__ask_history_after_reset.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "body": { + "messages": [], + "exchanges_used": 0, + "exchange_limit": 100, + "can_send": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__ask_history_after_send.json b/tests/fixtures/parity/canonical/account__ask_history_after_send.json new file mode 100644 index 0000000..ded388d --- /dev/null +++ b/tests/fixtures/parity/canonical/account__ask_history_after_send.json @@ -0,0 +1,25 @@ +{ + "status": 200, + "body": { + "messages": [ + { + "role": "user", + "content": "Why?", + "created_at": "2026-10-01T09:07:00.123456+00:00" + }, + { + "role": "expert", + "content": "Because **evidence**.", + "created_at": "2026-10-01T09:14:00.123456+00:00" + } + ], + "exchanges_used": 1, + "exchange_limit": 100, + "can_send": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__ask_history_empty.json b/tests/fixtures/parity/canonical/account__ask_history_empty.json new file mode 100644 index 0000000..e9962b2 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__ask_history_empty.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "body": { + "messages": [], + "exchanges_used": 0, + "exchange_limit": 100, + "can_send": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__ask_history_messages.json b/tests/fixtures/parity/canonical/account__ask_history_messages.json new file mode 100644 index 0000000..efc4809 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__ask_history_messages.json @@ -0,0 +1,25 @@ +{ + "status": 200, + "body": { + "messages": [ + { + "role": "user", + "content": "Hello", + "created_at": "2026-10-01T09:07:00.123456+00:00" + }, + { + "role": "expert", + "content": "Hi there!", + "created_at": "2026-10-01T09:14:00.123456+00:00" + } + ], + "exchanges_used": 0, + "exchange_limit": 100, + "can_send": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__ask_reset.json b/tests/fixtures/parity/canonical/account__ask_reset.json new file mode 100644 index 0000000..cddadae --- /dev/null +++ b/tests/fixtures/parity/canonical/account__ask_reset.json @@ -0,0 +1,11 @@ +{ + "status": 200, + "body": { + "ok": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__ask_send.json b/tests/fixtures/parity/canonical/account__ask_send.json new file mode 100644 index 0000000..d07ac92 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__ask_send.json @@ -0,0 +1,13 @@ +{ + "status": 200, + "body": { + "role": "expert", + "content": "Because **evidence**.", + "created_at": "2026-10-01T09:07:00.123456+00:00" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__ask_send_language.json b/tests/fixtures/parity/canonical/account__ask_send_language.json new file mode 100644 index 0000000..37c151c --- /dev/null +++ b/tests/fixtures/parity/canonical/account__ask_send_language.json @@ -0,0 +1,13 @@ +{ + "status": 200, + "body": { + "role": "expert", + "content": "Porque.", + "created_at": "2026-10-01T09:07:00.123456+00:00" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__library_empty.json b/tests/fixtures/parity/canonical/account__library_empty.json index b419316..406be8e 100644 --- a/tests/fixtures/parity/canonical/account__library_empty.json +++ b/tests/fixtures/parity/canonical/account__library_empty.json @@ -1,14 +1,14 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [], "total": 0, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__library_item_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/account__library_item_modified_at_crosses_midnight_by_minutes.json index 1045857..b9e2003 100644 --- a/tests/fixtures/parity/canonical/account__library_item_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/canonical/account__library_item_modified_at_crosses_midnight_by_minutes.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -26,5 +21,10 @@ "total": 1, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__library_item_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/account__library_item_modified_at_same_day_hours_apart.json index d4d580f..cd1c5f3 100644 --- a/tests/fixtures/parity/canonical/account__library_item_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/canonical/account__library_item_modified_at_same_day_hours_apart.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -26,5 +21,10 @@ "total": 1, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__library_items.json b/tests/fixtures/parity/canonical/account__library_items.json index e810be9..7939f55 100644 --- a/tests/fixtures/parity/canonical/account__library_items.json +++ b/tests/fixtures/parity/canonical/account__library_items.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -18,12 +13,12 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "language": "en" }, { - "verification_id": "7c83247c", + "verification_id": "4d44dfaf", "claim": "Library claim 1.", "domain": "Science", "entities": [], @@ -33,12 +28,12 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:28:00.123456+00:00", - "completed_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", "language": "en" }, { - "verification_id": "b79019e4", + "verification_id": "7c83247c", "claim": "Library claim 2.", "domain": "Science", "entities": [], @@ -48,13 +43,18 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:42:00.123456+00:00", - "completed_at": "2026-10-01T09:42:00.123456+00:00", + "created_at": "2026-10-01T09:21:00.123456+00:00", + "completed_at": "2026-10-01T09:21:00.123456+00:00", "language": "en" } ], "total": 3, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__library_no_match.json b/tests/fixtures/parity/canonical/account__library_no_match.json index b419316..406be8e 100644 --- a/tests/fixtures/parity/canonical/account__library_no_match.json +++ b/tests/fixtures/parity/canonical/account__library_no_match.json @@ -1,14 +1,14 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [], "total": 0, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__library_page_past_end.json b/tests/fixtures/parity/canonical/account__library_page_past_end.json index 86d64c7..575d59b 100644 --- a/tests/fixtures/parity/canonical/account__library_page_past_end.json +++ b/tests/fixtures/parity/canonical/account__library_page_past_end.json @@ -1,14 +1,14 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [], "total": 1, "page": 2, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__library_paginated_second_page.json b/tests/fixtures/parity/canonical/account__library_paginated_second_page.json index ae61ec7..e19a6d7 100644 --- a/tests/fixtures/parity/canonical/account__library_paginated_second_page.json +++ b/tests/fixtures/parity/canonical/account__library_paginated_second_page.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -18,12 +13,12 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "language": "en" }, { - "verification_id": "7c83247c", + "verification_id": "4d44dfaf", "claim": "Paged claim 021.", "domain": "", "entities": [], @@ -33,13 +28,18 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:28:00.123456+00:00", - "completed_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", "language": "en" } ], "total": 22, "page": 2, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__me_usage_extra_credits.json b/tests/fixtures/parity/canonical/account__me_usage_extra_credits.json index 14ab818..0bd9f0a 100644 --- a/tests/fixtures/parity/canonical/account__me_usage_extra_credits.json +++ b/tests/fixtures/parity/canonical/account__me_usage_extra_credits.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", @@ -13,7 +8,7 @@ "used": 0, "remaining": 350, "extra": 250, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -36,5 +31,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__me_usage_extra_only.json b/tests/fixtures/parity/canonical/account__me_usage_extra_only.json index 3b3e240..553553f 100644 --- a/tests/fixtures/parity/canonical/account__me_usage_extra_only.json +++ b/tests/fixtures/parity/canonical/account__me_usage_extra_only.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", @@ -13,7 +8,7 @@ "used": 100, "remaining": 37, "extra": 37, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -36,5 +31,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__me_usage_extract_calls.json b/tests/fixtures/parity/canonical/account__me_usage_extract_calls.json index 54303ab..0f0a7e3 100644 --- a/tests/fixtures/parity/canonical/account__me_usage_extract_calls.json +++ b/tests/fixtures/parity/canonical/account__me_usage_extract_calls.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", @@ -13,7 +8,7 @@ "used": 0, "remaining": 100, "extra": 0, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -36,5 +31,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__me_usage_free.json b/tests/fixtures/parity/canonical/account__me_usage_free.json index e9b9231..49d68a6 100644 --- a/tests/fixtures/parity/canonical/account__me_usage_free.json +++ b/tests/fixtures/parity/canonical/account__me_usage_free.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", @@ -13,7 +8,7 @@ "used": 0, "remaining": 100, "extra": 0, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -36,5 +31,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__me_usage_free_partly_spent.json b/tests/fixtures/parity/canonical/account__me_usage_free_partly_spent.json index d08a9ac..4ef2fed 100644 --- a/tests/fixtures/parity/canonical/account__me_usage_free_partly_spent.json +++ b/tests/fixtures/parity/canonical/account__me_usage_free_partly_spent.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", @@ -13,7 +8,7 @@ "used": 17, "remaining": 83, "extra": 0, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -36,5 +31,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__me_usage_oauth.json b/tests/fixtures/parity/canonical/account__me_usage_oauth.json new file mode 100644 index 0000000..49d68a6 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__me_usage_oauth.json @@ -0,0 +1,40 @@ +{ + "status": 200, + "body": { + "plan": "free", + "plan_label": "Free", + "credits": { + "total": 100, + "used": 0, + "remaining": 100, + "extra": 0, + "resets_at": "2026-10-01T14:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__me_usage_plus.json b/tests/fixtures/parity/canonical/account__me_usage_plus.json index 4a255a9..d1c06bf 100644 --- a/tests/fixtures/parity/canonical/account__me_usage_plus.json +++ b/tests/fixtures/parity/canonical/account__me_usage_plus.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "plus", "plan_label": "Plus", @@ -13,7 +8,7 @@ "used": 0, "remaining": 500, "extra": 0, - "resets_at": "2026-10-01T09:07:00.123456+00:00" + "resets_at": "2026-10-01T14:07:00.123456+00:00" }, "costs": { "verify": 10, @@ -36,5 +31,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__me_usage_pro.json b/tests/fixtures/parity/canonical/account__me_usage_pro.json index 943f796..0a9924e 100644 --- a/tests/fixtures/parity/canonical/account__me_usage_pro.json +++ b/tests/fixtures/parity/canonical/account__me_usage_pro.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "pro", "plan_label": "Pro", @@ -13,7 +8,7 @@ "used": 0, "remaining": 5000, "extra": 0, - "resets_at": "2026-10-01T09:07:00.123456+00:00" + "resets_at": "2026-10-01T14:07:00.123456+00:00" }, "costs": { "verify": 10, @@ -36,5 +31,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__me_usage_pro_extra.json b/tests/fixtures/parity/canonical/account__me_usage_pro_extra.json index 8f8d482..20a91fa 100644 --- a/tests/fixtures/parity/canonical/account__me_usage_pro_extra.json +++ b/tests/fixtures/parity/canonical/account__me_usage_pro_extra.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "pro", "plan_label": "Pro", @@ -13,7 +8,7 @@ "used": 0, "remaining": 6000, "extra": 1000, - "resets_at": "2026-10-01T09:07:00.123456+00:00" + "resets_at": "2026-10-01T14:07:00.123456+00:00" }, "costs": { "verify": 10, @@ -36,5 +31,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__me_usage_stale_quota_row.json b/tests/fixtures/parity/canonical/account__me_usage_stale_quota_row.json index e9b9231..49d68a6 100644 --- a/tests/fixtures/parity/canonical/account__me_usage_stale_quota_row.json +++ b/tests/fixtures/parity/canonical/account__me_usage_stale_quota_row.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", @@ -13,7 +8,7 @@ "used": 0, "remaining": 100, "extra": 0, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -36,5 +31,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/account__oauth_register_success.json b/tests/fixtures/parity/canonical/account__oauth_register_success.json new file mode 100644 index 0000000..15e9752 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__oauth_register_success.json @@ -0,0 +1,25 @@ +{ + "status": 201, + "body": { + "client_id": "lzc_0a1db81dbba84d2d473826d8", + "client_id_issued_at": "", + "client_name": "n8n", + "redirect_uris": [ + "https://acme.app.n8n.cloud/rest/oauth2-credential/callback" + ], + "grant_types": [ + "authorization_code", + "refresh_token" + ], + "response_types": [ + "code" + ], + "token_endpoint_auth_method": "none", + "scope": "assess verify ask ask:read extract history:read history:write usage:read webhooks:manage" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__oauth_revoke.json b/tests/fixtures/parity/canonical/account__oauth_revoke.json new file mode 100644 index 0000000..f0ea1e6 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__oauth_revoke.json @@ -0,0 +1,9 @@ +{ + "status": 200, + "body": {}, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__oauth_revoke_token.json b/tests/fixtures/parity/canonical/account__oauth_revoke_token.json new file mode 100644 index 0000000..f0ea1e6 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__oauth_revoke_token.json @@ -0,0 +1,9 @@ +{ + "status": 200, + "body": {}, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__webhook_secret_api_key.json b/tests/fixtures/parity/canonical/account__webhook_secret_api_key.json new file mode 100644 index 0000000..4fdb761 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__webhook_secret_api_key.json @@ -0,0 +1,12 @@ +{ + "status": 403, + "body": { + "detail": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.", + "code": "oauth_only" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__webhook_secret_insufficient_scope.json b/tests/fixtures/parity/canonical/account__webhook_secret_insufficient_scope.json new file mode 100644 index 0000000..6e2d697 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__webhook_secret_insufficient_scope.json @@ -0,0 +1,14 @@ +{ + "status": 403, + "body": { + "detail": "The access token does not allow this call.", + "code": "insufficient_scope", + "scope": "webhooks:manage" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "WWW-Authenticate": "Bearer error=\"insufficient_scope\", scope=\"webhooks:manage\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/account__webhook_secret_oauth.json b/tests/fixtures/parity/canonical/account__webhook_secret_oauth.json new file mode 100644 index 0000000..65ec897 --- /dev/null +++ b/tests/fixtures/parity/canonical/account__webhook_secret_oauth.json @@ -0,0 +1,11 @@ +{ + "status": 200, + "body": { + "webhook_secret": "dc06a4fb5512d77eb96f64eedf3ce77dff58de30e17140fbb229a3e048c3bb93" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/assess__401_no_key.json b/tests/fixtures/parity/canonical/assess__401_no_key.json index 1c3df51..dcdaad0 100644 --- a/tests/fixtures/parity/canonical/assess__401_no_key.json +++ b/tests/fixtures/parity/canonical/assess__401_no_key.json @@ -1,12 +1,12 @@ { "status": 401, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized", - "code": "not_authenticated" } } diff --git a/tests/fixtures/parity/canonical/assess__402_no_credits.json b/tests/fixtures/parity/canonical/assess__402_no_credits.json index 5e931cc..c64d322 100644 --- a/tests/fixtures/parity/canonical/assess__402_no_credits.json +++ b/tests/fixtures/parity/canonical/assess__402_no_credits.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining /assess units.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__422_blank_item.json b/tests/fixtures/parity/canonical/assess__422_blank_item.json index db514d2..f5dbd88 100644 --- a/tests/fixtures/parity/canonical/assess__422_blank_item.json +++ b/tests/fixtures/parity/canonical/assess__422_blank_item.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claims[1] is blank.", "code": "blank_input", @@ -19,5 +14,10 @@ "type": "blank_input" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__422_blank_text.json b/tests/fixtures/parity/canonical/assess__422_blank_text.json index a5a1062..bfcc575 100644 --- a/tests/fixtures/parity/canonical/assess__422_blank_text.json +++ b/tests/fixtures/parity/canonical/assess__422_blank_text.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claim is required.", "code": "blank_input", @@ -18,5 +13,10 @@ "type": "blank_input" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__422_input_conflict.json b/tests/fixtures/parity/canonical/assess__422_input_conflict.json index a46942a..1746713 100644 --- a/tests/fixtures/parity/canonical/assess__422_input_conflict.json +++ b/tests/fixtures/parity/canonical/assess__422_input_conflict.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Send either `claim` (one text) or `claims` (a list of claims), not both.", "code": "input_conflict", @@ -18,5 +13,10 @@ "type": "input_conflict" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__422_item_too_long.json b/tests/fixtures/parity/canonical/assess__422_item_too_long.json index 137d44e..1408fdd 100644 --- a/tests/fixtures/parity/canonical/assess__422_item_too_long.json +++ b/tests/fixtures/parity/canonical/assess__422_item_too_long.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claims[1] is 2001 characters; each claim may be at most 2000. Send a document to /extract first, then assess its claims.", "code": "item_too_long", @@ -19,5 +14,10 @@ "type": "item_too_long" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__422_no_input_field.json b/tests/fixtures/parity/canonical/assess__422_no_input_field.json index 9136471..f5b9868 100644 --- a/tests/fixtures/parity/canonical/assess__422_no_input_field.json +++ b/tests/fixtures/parity/canonical/assess__422_no_input_field.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claim: Field required", "code": "validation_error", @@ -19,5 +14,10 @@ "type": "missing" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__422_too_many_items.json b/tests/fixtures/parity/canonical/assess__422_too_many_items.json index 3468b9e..1c4170f 100644 --- a/tests/fixtures/parity/canonical/assess__422_too_many_items.json +++ b/tests/fixtures/parity/canonical/assess__422_too_many_items.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "At most 20 claims per call; got 21. Split the list.", "code": "too_many_items", @@ -18,5 +13,10 @@ "type": "too_many_items" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__422_wrong_type_claim.json b/tests/fixtures/parity/canonical/assess__422_wrong_type_claim.json index acbd190..78a4682 100644 --- a/tests/fixtures/parity/canonical/assess__422_wrong_type_claim.json +++ b/tests/fixtures/parity/canonical/assess__422_wrong_type_claim.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claim: Input should be a valid string", "code": "validation_error", @@ -19,5 +14,10 @@ "type": "string_type" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__422_wrong_type_claims.json b/tests/fixtures/parity/canonical/assess__422_wrong_type_claims.json index 2b44c06..479b4ca 100644 --- a/tests/fixtures/parity/canonical/assess__422_wrong_type_claims.json +++ b/tests/fixtures/parity/canonical/assess__422_wrong_type_claims.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claims: Input should be a valid list", "code": "validation_error", @@ -19,5 +14,10 @@ "type": "list_type" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__502_framing_failed.json b/tests/fixtures/parity/canonical/assess__502_framing_failed.json index e671a1e..3e9296d 100644 --- a/tests/fixtures/parity/canonical/assess__502_framing_failed.json +++ b/tests/fixtures/parity/canonical/assess__502_framing_failed.json @@ -1,12 +1,12 @@ { "status": 502, + "body": { + "detail": "Framing failed", + "code": "framing_failed" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Framing failed", - "code": "framing_failed" } } diff --git a/tests/fixtures/parity/canonical/assess__503_capacity.json b/tests/fixtures/parity/canonical/assess__503_capacity.json index 343e0e1..b10c32e 100644 --- a/tests/fixtures/parity/canonical/assess__503_capacity.json +++ b/tests/fixtures/parity/canonical/assess__503_capacity.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "100", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": 100, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "100", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__503_list_all_upstream_unavailable.json b/tests/fixtures/parity/canonical/assess__503_list_all_upstream_unavailable.json index c19b99f..f4be3f0 100644 --- a/tests/fixtures/parity/canonical/assess__503_list_all_upstream_unavailable.json +++ b/tests/fixtures/parity/canonical/assess__503_list_all_upstream_unavailable.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Our model providers are temporarily unavailable. Please retry shortly. Nothing was charged.", "code": "upstream_unavailable", "retry_after": 90, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__503_upstream_unavailable.json b/tests/fixtures/parity/canonical/assess__503_upstream_unavailable.json index 3315806..be8c7a9 100644 --- a/tests/fixtures/parity/canonical/assess__503_upstream_unavailable.json +++ b/tests/fixtures/parity/canonical/assess__503_upstream_unavailable.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Our model providers are temporarily unavailable. Please retry shortly.", "code": "upstream_unavailable", "retry_after": 90, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__deep_tier_hit.json b/tests/fixtures/parity/canonical/assess__deep_tier_hit.json index 0a05b10..e988914 100644 --- a/tests/fixtures/parity/canonical/assess__deep_tier_hit.json +++ b/tests/fixtures/parity/canonical/assess__deep_tier_hit.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ok", "claims": [ @@ -24,5 +19,10 @@ ], "failure": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__idempotency_body_mismatch.json b/tests/fixtures/parity/canonical/assess__idempotency_body_mismatch.json index e20089e..8cdd4be 100644 --- a/tests/fixtures/parity/canonical/assess__idempotency_body_mismatch.json +++ b/tests/fixtures/parity/canonical/assess__idempotency_body_mismatch.json @@ -1,12 +1,12 @@ { "status": 422, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Idempotency-Key reused with a different request body.", - "code": "idempotency_body_mismatch" } } diff --git a/tests/fixtures/parity/canonical/assess__idempotency_first.json b/tests/fixtures/parity/canonical/assess__idempotency_first.json index 8c05be0..72c4d4a 100644 --- a/tests/fixtures/parity/canonical/assess__idempotency_first.json +++ b/tests/fixtures/parity/canonical/assess__idempotency_first.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ok", "claims": [ @@ -24,5 +19,10 @@ ], "failure": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__idempotency_replay.json b/tests/fixtures/parity/canonical/assess__idempotency_replay.json index 8c05be0..72c4d4a 100644 --- a/tests/fixtures/parity/canonical/assess__idempotency_replay.json +++ b/tests/fixtures/parity/canonical/assess__idempotency_replay.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ok", "claims": [ @@ -24,5 +19,10 @@ ], "failure": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__list_all_error_rows.json b/tests/fixtures/parity/canonical/assess__list_all_error_rows.json index 75ced45..f0fc834 100644 --- a/tests/fixtures/parity/canonical/assess__list_all_error_rows.json +++ b/tests/fixtures/parity/canonical/assess__list_all_error_rows.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "no_checkable_claim", "claims": [ @@ -51,5 +46,10 @@ ], "failure": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__list_compound_item.json b/tests/fixtures/parity/canonical/assess__list_compound_item.json index 536868b..ed32e13 100644 --- a/tests/fixtures/parity/canonical/assess__list_compound_item.json +++ b/tests/fixtures/parity/canonical/assess__list_compound_item.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ok", "claims": [ @@ -40,5 +35,10 @@ ], "failure": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__list_mixed_rows.json b/tests/fixtures/parity/canonical/assess__list_mixed_rows.json index 5cec126..7b5a292 100644 --- a/tests/fixtures/parity/canonical/assess__list_mixed_rows.json +++ b/tests/fixtures/parity/canonical/assess__list_mixed_rows.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ok", "claims": [ @@ -84,5 +79,10 @@ ], "failure": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__memo_hit.json b/tests/fixtures/parity/canonical/assess__memo_hit.json index 873c763..5484c2e 100644 --- a/tests/fixtures/parity/canonical/assess__memo_hit.json +++ b/tests/fixtures/parity/canonical/assess__memo_hit.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ok", "claims": [ @@ -24,5 +19,10 @@ ], "failure": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__replay_later_200.json b/tests/fixtures/parity/canonical/assess__replay_later_200.json index bac5c15..fedc9c5 100644 --- a/tests/fixtures/parity/canonical/assess__replay_later_200.json +++ b/tests/fixtures/parity/canonical/assess__replay_later_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -24,5 +19,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__single_no_claim.json b/tests/fixtures/parity/canonical/assess__single_no_claim.json index 3a193c0..aea089f 100644 --- a/tests/fixtures/parity/canonical/assess__single_no_claim.json +++ b/tests/fixtures/parity/canonical/assess__single_no_claim.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "no_checkable_claim", "claims": [], @@ -17,5 +12,10 @@ "docs_url": "https://lenz.io/docs/errors#invalid-input" }, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__single_one_claim.json b/tests/fixtures/parity/canonical/assess__single_one_claim.json index d27ac90..2c30b26 100644 --- a/tests/fixtures/parity/canonical/assess__single_one_claim.json +++ b/tests/fixtures/parity/canonical/assess__single_one_claim.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ok", "claims": [ @@ -24,5 +19,10 @@ ], "failure": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__single_text_over_wave_more_claims.json b/tests/fixtures/parity/canonical/assess__single_text_over_wave_more_claims.json index 1d4fc2e..224f888 100644 --- a/tests/fixtures/parity/canonical/assess__single_text_over_wave_more_claims.json +++ b/tests/fixtures/parity/canonical/assess__single_text_over_wave_more_claims.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ok", "claims": [ @@ -274,5 +269,10 @@ "Claim number 20 is documented.", "Claim number 21 is documented." ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__single_text_several_claims.json b/tests/fixtures/parity/canonical/assess__single_text_several_claims.json index 4313609..e2e6e8c 100644 --- a/tests/fixtures/parity/canonical/assess__single_text_several_claims.json +++ b/tests/fixtures/parity/canonical/assess__single_text_several_claims.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ok", "claims": [ @@ -50,5 +45,10 @@ ], "failure": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/assess__suggest_rewrite.json b/tests/fixtures/parity/canonical/assess__suggest_rewrite.json index d2aee3e..3df8c25 100644 --- a/tests/fixtures/parity/canonical/assess__suggest_rewrite.json +++ b/tests/fixtures/parity/canonical/assess__suggest_rewrite.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ok", "claims": [ @@ -37,5 +32,10 @@ ], "failure": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__402_no_credits.json b/tests/fixtures/parity/canonical/citecheck__402_no_credits.json index dfb7db4..5d36059 100644 --- a/tests/fixtures/parity/canonical/citecheck__402_no_credits.json +++ b/tests/fixtures/parity/canonical/citecheck__402_no_credits.json @@ -1,18 +1,18 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining credits for citation checks.", "code": "no_credits", "docs_url": "https://lenz.io/docs/errors#quota", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 100, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_empty_body.json b/tests/fixtures/parity/canonical/citecheck__422_empty_body.json index 82cdb99..8e95f6b 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_empty_body.json +++ b/tests/fixtures/parity/canonical/citecheck__422_empty_body.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload: Value error, send exactly one of text and pairs", "code": "validation_error", @@ -21,5 +16,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_invalid_doi.json b/tests/fixtures/parity/canonical/citecheck__422_invalid_doi.json index c3c1d4c..def6efd 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_invalid_doi.json +++ b/tests/fixtures/parity/canonical/citecheck__422_invalid_doi.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "pairs[0].doi: Send the DOI alone, like 10.1038/nature12373.", "code": "invalid_doi", @@ -21,5 +16,10 @@ "type": "invalid_doi" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_max_citations_over_20.json b/tests/fixtures/parity/canonical/citecheck__422_max_citations_over_20.json index 610a9cd..bbc3599 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_max_citations_over_20.json +++ b/tests/fixtures/parity/canonical/citecheck__422_max_citations_over_20.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "max_citations: Input should be less than or equal to 20", "code": "validation_error", @@ -22,5 +17,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_max_citations_with_pairs.json b/tests/fixtures/parity/canonical/citecheck__422_max_citations_with_pairs.json index 746f21f..5fb4268 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_max_citations_with_pairs.json +++ b/tests/fixtures/parity/canonical/citecheck__422_max_citations_with_pairs.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload: Value error, max_citations goes with text: every pair is checked", "code": "validation_error", @@ -21,5 +16,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_pair_bad_url_scheme.json b/tests/fixtures/parity/canonical/citecheck__422_pair_bad_url_scheme.json index a791f53..10bcd15 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_pair_bad_url_scheme.json +++ b/tests/fixtures/parity/canonical/citecheck__422_pair_bad_url_scheme.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "pairs[0].url: Value error, url: an http or https link", "code": "validation_error", @@ -24,5 +19,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_pair_no_source.json b/tests/fixtures/parity/canonical/citecheck__422_pair_no_source.json index f7ac540..038c0b4 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_pair_no_source.json +++ b/tests/fixtures/parity/canonical/citecheck__422_pair_no_source.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "pairs[0]: Value error, send exactly one of url and doi", "code": "validation_error", @@ -23,5 +18,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_pair_url_and_doi.json b/tests/fixtures/parity/canonical/citecheck__422_pair_url_and_doi.json index f7ac540..038c0b4 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_pair_url_and_doi.json +++ b/tests/fixtures/parity/canonical/citecheck__422_pair_url_and_doi.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "pairs[0]: Value error, send exactly one of url and doi", "code": "validation_error", @@ -23,5 +18,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_pairs_empty.json b/tests/fixtures/parity/canonical/citecheck__422_pairs_empty.json index 9b2008e..33dbd42 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_pairs_empty.json +++ b/tests/fixtures/parity/canonical/citecheck__422_pairs_empty.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "pairs: Value error, pairs: 1 to 20 items", "code": "validation_error", @@ -22,5 +17,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_pairs_over_20.json b/tests/fixtures/parity/canonical/citecheck__422_pairs_over_20.json index 9b2008e..33dbd42 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_pairs_over_20.json +++ b/tests/fixtures/parity/canonical/citecheck__422_pairs_over_20.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "pairs: Value error, pairs: 1 to 20 items", "code": "validation_error", @@ -22,5 +17,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_quote_not_in_statement.json b/tests/fixtures/parity/canonical/citecheck__422_quote_not_in_statement.json index e4d2408..543ee02 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_quote_not_in_statement.json +++ b/tests/fixtures/parity/canonical/citecheck__422_quote_not_in_statement.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "pairs[0]: Each quote must be words of its statement.", "code": "quote_not_in_statement", @@ -20,5 +15,10 @@ "type": "quote_not_in_statement" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_text_and_pairs.json b/tests/fixtures/parity/canonical/citecheck__422_text_and_pairs.json index 82cdb99..8e95f6b 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_text_and_pairs.json +++ b/tests/fixtures/parity/canonical/citecheck__422_text_and_pairs.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload: Value error, send exactly one of text and pairs", "code": "validation_error", @@ -21,5 +16,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_unknown_field.json b/tests/fixtures/parity/canonical/citecheck__422_unknown_field.json index 0aed242..0823167 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_unknown_field.json +++ b/tests/fixtures/parity/canonical/citecheck__422_unknown_field.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "pairs[0].extra: Extra inputs are not permitted", "code": "validation_error", @@ -21,5 +16,10 @@ "type": "extra_forbidden" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_url_input.json b/tests/fixtures/parity/canonical/citecheck__422_url_input.json index 816edbe..68e0bdf 100644 --- a/tests/fixtures/parity/canonical/citecheck__422_url_input.json +++ b/tests/fixtures/parity/canonical/citecheck__422_url_input.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Send the page's text, with its links, to check the sources it cites.", "code": "url_input", @@ -18,5 +13,10 @@ "type": "url_input" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__422_webhook_secret_missing.json b/tests/fixtures/parity/canonical/citecheck__422_webhook_secret_missing.json new file mode 100644 index 0000000..3286c6c --- /dev/null +++ b/tests/fixtures/parity/canonical/citecheck__422_webhook_secret_missing.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "body": { + "detail": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "code": "webhook_secret_missing", + "errors": [ + { + "loc": [ + "body", + "webhook_url" + ], + "msg": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "type": "webhook_secret_missing" + } + ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/citecheck__429_citecheck_in_flight.json b/tests/fixtures/parity/canonical/citecheck__429_citecheck_in_flight.json index fa73820..ec8db9b 100644 --- a/tests/fixtures/parity/canonical/citecheck__429_citecheck_in_flight.json +++ b/tests/fixtures/parity/canonical/citecheck__429_citecheck_in_flight.json @@ -1,14 +1,14 @@ { "status": 429, + "body": { + "detail": "This account already has 3 citation checks running. Wait for one to finish.", + "code": "citecheck_in_flight", + "retry_after": 60 + }, "headers": { "Content-Type": "application/json", "Retry-After": "60", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "This account already has 3 citation checks running. Wait for one to finish.", - "code": "citecheck_in_flight", - "retry_after": 60 } } diff --git a/tests/fixtures/parity/canonical/citecheck__503_capacity.json b/tests/fixtures/parity/canonical/citecheck__503_capacity.json index bcff7db..63b5d1c 100644 --- a/tests/fixtures/parity/canonical/citecheck__503_capacity.json +++ b/tests/fixtures/parity/canonical/citecheck__503_capacity.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": 90, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__503_citations_unavailable.json b/tests/fixtures/parity/canonical/citecheck__503_citations_unavailable.json index cdeb748..6f3c66e 100644 --- a/tests/fixtures/parity/canonical/citecheck__503_citations_unavailable.json +++ b/tests/fixtures/parity/canonical/citecheck__503_citations_unavailable.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "300", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Citation checking is switched off right now. Retry later; nothing was charged.", "code": "citations_unavailable", "retry_after": 300, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "300", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_404_not_found.json b/tests/fixtures/parity/canonical/citecheck__get_404_not_found.json index e0adfb3..5aa3709 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_404_not_found.json +++ b/tests/fixtures/parity/canonical/citecheck__get_404_not_found.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Citation check not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Citation check not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_404_review_id.json b/tests/fixtures/parity/canonical/citecheck__get_404_review_id.json index e0adfb3..5aa3709 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_404_review_id.json +++ b/tests/fixtures/parity/canonical/citecheck__get_404_review_id.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Citation check not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Citation check not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_410_purged.json b/tests/fixtures/parity/canonical/citecheck__get_410_purged.json index 9fff981..08b9585 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_410_purged.json +++ b/tests/fixtures/parity/canonical/citecheck__get_410_purged.json @@ -1,13 +1,13 @@ { "status": 410, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This check is no longer available: its account removes content after a set period.", "code": "purged", "purged_at": "2026-10-01T09:07:00.123456Z" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_checking.json b/tests/fixtures/parity/canonical/citecheck__get_checking.json index 9ca9e92..9205f4d 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_checking.json +++ b/tests/fixtures/parity/canonical/citecheck__get_checking.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "checking", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "poll_after_seconds": 10, @@ -99,5 +94,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_clean.json b/tests/fixtures/parity/canonical/citecheck__get_completed_clean.json index 11e7ed2..a80bfd4 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_completed_clean.json +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_clean.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -107,5 +102,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_doi_pair.json b/tests/fixtures/parity/canonical/citecheck__get_completed_doi_pair.json index 49e62df..c169837 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_completed_doi_pair.json +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_doi_pair.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -72,5 +67,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_incomplete.json b/tests/fixtures/parity/canonical/citecheck__get_completed_incomplete.json index a50708c..02db48c 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_completed_incomplete.json +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_incomplete.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -125,5 +120,10 @@ ], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_issues_found.json b/tests/fixtures/parity/canonical/citecheck__get_completed_issues_found.json index 1555b9a..6be9e27 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_completed_issues_found.json +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_issues_found.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -137,5 +132,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_partly_supported.json b/tests/fixtures/parity/canonical/citecheck__get_completed_partly_supported.json index f1d95be..dc8d58a 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_completed_partly_supported.json +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_partly_supported.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -107,5 +102,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_completed_unchecked.json b/tests/fixtures/parity/canonical/citecheck__get_completed_unchecked.json index a37c4cb..0eb98a2 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_completed_unchecked.json +++ b/tests/fixtures/parity/canonical/citecheck__get_completed_unchecked.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -107,5 +102,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_failed_no_citations.json b/tests/fixtures/parity/canonical/citecheck__get_failed_no_citations.json index 25625db..29d977a 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_failed_no_citations.json +++ b/tests/fixtures/parity/canonical/citecheck__get_failed_no_citations.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -39,5 +34,10 @@ "docs_url": "https://lenz.io/docs/errors#invalid-input" }, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_failed_upstream_unavailable.json b/tests/fixtures/parity/canonical/citecheck__get_failed_upstream_unavailable.json index a323d29..d5ee990 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_failed_upstream_unavailable.json +++ b/tests/fixtures/parity/canonical/citecheck__get_failed_upstream_unavailable.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -149,5 +144,10 @@ "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" }, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_queued.json b/tests/fixtures/parity/canonical/citecheck__get_queued.json index df7dfee..946e493 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_queued.json +++ b/tests/fixtures/parity/canonical/citecheck__get_queued.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "queued", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "poll_after_seconds": 10, @@ -68,5 +63,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_text_limit_exactly_at_limit.json b/tests/fixtures/parity/canonical/citecheck__get_text_limit_exactly_at_limit.json index 600d1b9..403ac29 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_text_limit_exactly_at_limit.json +++ b/tests/fixtures/parity/canonical/citecheck__get_text_limit_exactly_at_limit.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -115,5 +110,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__get_text_limit_reached.json b/tests/fixtures/parity/canonical/citecheck__get_text_limit_reached.json index a4dbb6b..279af9f 100644 --- a/tests/fixtures/parity/canonical/citecheck__get_text_limit_reached.json +++ b/tests/fixtures/parity/canonical/citecheck__get_text_limit_reached.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -89,5 +84,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__idempotency_body_mismatch_422.json b/tests/fixtures/parity/canonical/citecheck__idempotency_body_mismatch_422.json index e20089e..8cdd4be 100644 --- a/tests/fixtures/parity/canonical/citecheck__idempotency_body_mismatch_422.json +++ b/tests/fixtures/parity/canonical/citecheck__idempotency_body_mismatch_422.json @@ -1,12 +1,12 @@ { "status": 422, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Idempotency-Key reused with a different request body.", - "code": "idempotency_body_mismatch" } } diff --git a/tests/fixtures/parity/canonical/citecheck__idempotency_conflict_409.json b/tests/fixtures/parity/canonical/citecheck__idempotency_conflict_409.json index 3978a83..c29d230 100644 --- a/tests/fixtures/parity/canonical/citecheck__idempotency_conflict_409.json +++ b/tests/fixtures/parity/canonical/citecheck__idempotency_conflict_409.json @@ -1,13 +1,13 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "A check with this Idempotency-Key is still being created. Retry shortly.", "code": "idempotency_conflict", "citecheck_id": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/citecheck__idempotent_replay_202.json b/tests/fixtures/parity/canonical/citecheck__idempotent_replay_202.json index 864551e..43d3598 100644 --- a/tests/fixtures/parity/canonical/citecheck__idempotent_replay_202.json +++ b/tests/fixtures/parity/canonical/citecheck__idempotent_replay_202.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/citechecks/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "citecheck_id": "8eb49302", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/citecheck__receipt_202.json b/tests/fixtures/parity/canonical/citecheck__receipt_202.json index 864551e..43d3598 100644 --- a/tests/fixtures/parity/canonical/citecheck__receipt_202.json +++ b/tests/fixtures/parity/canonical/citecheck__receipt_202.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/citechecks/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "citecheck_id": "8eb49302", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/citecheck__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/canonical/citecheck__receipt_202_empty_webhook_url.json index 864551e..43d3598 100644 --- a/tests/fixtures/parity/canonical/citecheck__receipt_202_empty_webhook_url.json +++ b/tests/fixtures/parity/canonical/citecheck__receipt_202_empty_webhook_url.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/citechecks/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "citecheck_id": "8eb49302", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/errors__ask_bad_language.json b/tests/fixtures/parity/canonical/errors__ask_bad_language.json index e543e6d..cf9c91d 100644 --- a/tests/fixtures/parity/canonical/errors__ask_bad_language.json +++ b/tests/fixtures/parity/canonical/errors__ask_bad_language.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Unsupported language 'xx-nope'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", "code": "unsupported_language", @@ -18,5 +13,10 @@ "type": "unsupported_language" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__ask_empty_message.json b/tests/fixtures/parity/canonical/errors__ask_empty_message.json index 86f7435..1b1c071 100644 --- a/tests/fixtures/parity/canonical/errors__ask_empty_message.json +++ b/tests/fixtures/parity/canonical/errors__ask_empty_message.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Message cannot be empty.", "code": "blank_input", @@ -18,5 +13,10 @@ "type": "blank_input" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__ask_failed.json b/tests/fixtures/parity/canonical/errors__ask_failed.json index df45b1c..a3b433f 100644 --- a/tests/fixtures/parity/canonical/errors__ask_failed.json +++ b/tests/fixtures/parity/canonical/errors__ask_failed.json @@ -1,12 +1,12 @@ { "status": 502, + "body": { + "detail": "The chat model could not answer this question.", + "code": "ask_failed" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "The chat model could not answer this question.", - "code": "ask_failed" } } diff --git a/tests/fixtures/parity/canonical/errors__ask_idempotency_key_reused.json b/tests/fixtures/parity/canonical/errors__ask_idempotency_key_reused.json index e20089e..8cdd4be 100644 --- a/tests/fixtures/parity/canonical/errors__ask_idempotency_key_reused.json +++ b/tests/fixtures/parity/canonical/errors__ask_idempotency_key_reused.json @@ -1,12 +1,12 @@ { "status": 422, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Idempotency-Key reused with a different request body.", - "code": "idempotency_body_mismatch" } } diff --git a/tests/fixtures/parity/canonical/errors__ask_message_too_long.json b/tests/fixtures/parity/canonical/errors__ask_message_too_long.json index 80b5bab..e982806 100644 --- a/tests/fixtures/parity/canonical/errors__ask_message_too_long.json +++ b/tests/fixtures/parity/canonical/errors__ask_message_too_long.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Message too long (max 500 characters).", "code": "validation_error", @@ -18,5 +13,10 @@ "type": "validation_error" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__ask_not_completed.json b/tests/fixtures/parity/canonical/errors__ask_not_completed.json index 9800c71..ad4b430 100644 --- a/tests/fixtures/parity/canonical/errors__ask_not_completed.json +++ b/tests/fixtures/parity/canonical/errors__ask_not_completed.json @@ -1,12 +1,12 @@ { "status": 400, + "body": { + "detail": "Ask is only available for completed verifications.", + "code": "verification_not_ready" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Ask is only available for completed verifications.", - "code": "verification_not_ready" } } diff --git a/tests/fixtures/parity/canonical/errors__ask_reset_not_found.json b/tests/fixtures/parity/canonical/errors__ask_reset_not_found.json index 3eec577..bccfc47 100644 --- a/tests/fixtures/parity/canonical/errors__ask_reset_not_found.json +++ b/tests/fixtures/parity/canonical/errors__ask_reset_not_found.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Verification not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Verification not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/errors__ask_send_not_found.json b/tests/fixtures/parity/canonical/errors__ask_send_not_found.json index 3eec577..bccfc47 100644 --- a/tests/fixtures/parity/canonical/errors__ask_send_not_found.json +++ b/tests/fixtures/parity/canonical/errors__ask_send_not_found.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Verification not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Verification not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/errors__auth_bad_key.json b/tests/fixtures/parity/canonical/errors__auth_bad_key.json index 1c3df51..dcdaad0 100644 --- a/tests/fixtures/parity/canonical/errors__auth_bad_key.json +++ b/tests/fixtures/parity/canonical/errors__auth_bad_key.json @@ -1,12 +1,12 @@ { "status": 401, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized", - "code": "not_authenticated" } } diff --git a/tests/fixtures/parity/canonical/errors__auth_bad_oauth_token.json b/tests/fixtures/parity/canonical/errors__auth_bad_oauth_token.json new file mode 100644 index 0000000..cc8ef29 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_bad_oauth_token.json @@ -0,0 +1,13 @@ +{ + "status": 401, + "body": { + "detail": "The access token is invalid, expired or revoked.", + "code": "invalid_token" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "WWW-Authenticate": "Bearer error=\"invalid_token\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_basic_scheme.json b/tests/fixtures/parity/canonical/errors__auth_basic_scheme.json index 1c3df51..dcdaad0 100644 --- a/tests/fixtures/parity/canonical/errors__auth_basic_scheme.json +++ b/tests/fixtures/parity/canonical/errors__auth_basic_scheme.json @@ -1,12 +1,12 @@ { "status": 401, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized", - "code": "not_authenticated" } } diff --git a/tests/fixtures/parity/canonical/errors__auth_expired_oauth_token.json b/tests/fixtures/parity/canonical/errors__auth_expired_oauth_token.json new file mode 100644 index 0000000..cc8ef29 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_expired_oauth_token.json @@ -0,0 +1,13 @@ +{ + "status": 401, + "body": { + "detail": "The access token is invalid, expired or revoked.", + "code": "invalid_token" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "WWW-Authenticate": "Bearer error=\"invalid_token\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_insufficient_scope.json b/tests/fixtures/parity/canonical/errors__auth_insufficient_scope.json index 15b8696..4c2fcdd 100644 --- a/tests/fixtures/parity/canonical/errors__auth_insufficient_scope.json +++ b/tests/fixtures/parity/canonical/errors__auth_insufficient_scope.json @@ -1,14 +1,14 @@ { "status": 403, + "body": { + "detail": "The access token does not allow this call.", + "code": "insufficient_scope", + "scope": "verify" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "WWW-Authenticate": "Bearer error=\"insufficient_scope\", scope=\"verify\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "The access token does not allow this call.", - "code": "insufficient_scope", - "scope": "verify" } } diff --git a/tests/fixtures/parity/canonical/errors__auth_missing_bearer.json b/tests/fixtures/parity/canonical/errors__auth_missing_bearer.json index 1c3df51..dcdaad0 100644 --- a/tests/fixtures/parity/canonical/errors__auth_missing_bearer.json +++ b/tests/fixtures/parity/canonical/errors__auth_missing_bearer.json @@ -1,12 +1,12 @@ { "status": 401, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized", - "code": "not_authenticated" } } diff --git a/tests/fixtures/parity/canonical/errors__auth_missing_bearer_post.json b/tests/fixtures/parity/canonical/errors__auth_missing_bearer_post.json index 1c3df51..dcdaad0 100644 --- a/tests/fixtures/parity/canonical/errors__auth_missing_bearer_post.json +++ b/tests/fixtures/parity/canonical/errors__auth_missing_bearer_post.json @@ -1,12 +1,12 @@ { "status": 401, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized", - "code": "not_authenticated" } } diff --git a/tests/fixtures/parity/canonical/errors__auth_oauth_issuer_off.json b/tests/fixtures/parity/canonical/errors__auth_oauth_issuer_off.json new file mode 100644 index 0000000..dcdaad0 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_oauth_issuer_off.json @@ -0,0 +1,12 @@ +{ + "status": 401, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_oauth_only.json b/tests/fixtures/parity/canonical/errors__auth_oauth_only.json new file mode 100644 index 0000000..4fdb761 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__auth_oauth_only.json @@ -0,0 +1,12 @@ +{ + "status": 403, + "body": { + "detail": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.", + "code": "oauth_only" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_history.json b/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_history.json index 3445e87..07faa70 100644 --- a/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_history.json +++ b/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_history.json @@ -1,12 +1,12 @@ { "status": 403, + "body": { + "detail": "This report is private.", + "code": "private_claim" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "This report is private.", - "code": "private_claim" } } diff --git a/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_send.json b/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_send.json index 3445e87..07faa70 100644 --- a/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_send.json +++ b/tests/fixtures/parity/canonical/errors__auth_private_claim_ask_send.json @@ -1,12 +1,12 @@ { "status": 403, + "body": { + "detail": "This report is private.", + "code": "private_claim" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "This report is private.", - "code": "private_claim" } } diff --git a/tests/fixtures/parity/canonical/errors__auth_unrecognised_prefix.json b/tests/fixtures/parity/canonical/errors__auth_unrecognised_prefix.json index 1c3df51..dcdaad0 100644 --- a/tests/fixtures/parity/canonical/errors__auth_unrecognised_prefix.json +++ b/tests/fixtures/parity/canonical/errors__auth_unrecognised_prefix.json @@ -1,12 +1,12 @@ { "status": 401, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized", - "code": "not_authenticated" } } diff --git a/tests/fixtures/parity/canonical/errors__http_error_library_bad_curated.json b/tests/fixtures/parity/canonical/errors__http_error_library_bad_curated.json index 76cbe7a..30b9871 100644 --- a/tests/fixtures/parity/canonical/errors__http_error_library_bad_curated.json +++ b/tests/fixtures/parity/canonical/errors__http_error_library_bad_curated.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Invalid curated list(s). Allowed: trivia", "code": "validation_error", @@ -18,5 +13,10 @@ "type": "validation_error" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__http_error_library_bad_verdict.json b/tests/fixtures/parity/canonical/errors__http_error_library_bad_verdict.json index 09dbe2e..c77d681 100644 --- a/tests/fixtures/parity/canonical/errors__http_error_library_bad_verdict.json +++ b/tests/fixtures/parity/canonical/errors__http_error_library_bad_verdict.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Invalid verdict label(s). Allowed: False, Mostly False, Mixed, Mostly True, True", "code": "validation_error", @@ -18,5 +13,10 @@ "type": "validation_error" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__method_not_allowed_get_verify.json b/tests/fixtures/parity/canonical/errors__method_not_allowed_get_verify.json new file mode 100644 index 0000000..7b3ec88 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__method_not_allowed_get_verify.json @@ -0,0 +1,12 @@ +{ + "status": 405, + "body": { + "detail": "Method not allowed.", + "code": "method_not_allowed" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__method_not_allowed_post_library.json b/tests/fixtures/parity/canonical/errors__method_not_allowed_post_library.json new file mode 100644 index 0000000..7b3ec88 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__method_not_allowed_post_library.json @@ -0,0 +1,12 @@ +{ + "status": 405, + "body": { + "detail": "Method not allowed.", + "code": "method_not_allowed" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__not_found_ask.json b/tests/fixtures/parity/canonical/errors__not_found_ask.json index 3eec577..bccfc47 100644 --- a/tests/fixtures/parity/canonical/errors__not_found_ask.json +++ b/tests/fixtures/parity/canonical/errors__not_found_ask.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Verification not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Verification not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/errors__not_found_route.json b/tests/fixtures/parity/canonical/errors__not_found_route.json index f1a8c33..775d847 100644 --- a/tests/fixtures/parity/canonical/errors__not_found_route.json +++ b/tests/fixtures/parity/canonical/errors__not_found_route.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/errors__not_found_verification.json b/tests/fixtures/parity/canonical/errors__not_found_verification.json index f1a8c33..775d847 100644 --- a/tests/fixtures/parity/canonical/errors__not_found_verification.json +++ b/tests/fixtures/parity/canonical/errors__not_found_verification.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/errors__not_found_verify_status.json b/tests/fixtures/parity/canonical/errors__not_found_verify_status.json index ed0bc13..8c0eaee 100644 --- a/tests/fixtures/parity/canonical/errors__not_found_verify_status.json +++ b/tests/fixtures/parity/canonical/errors__not_found_verify_status.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Task not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Task not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/errors__oauth_register_disabled.json b/tests/fixtures/parity/canonical/errors__oauth_register_disabled.json new file mode 100644 index 0000000..a16648d --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__oauth_register_disabled.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "body": { + "": "" + }, + "headers": { + "Content-Type": "text/html; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__oauth_register_invalid_client_metadata.json b/tests/fixtures/parity/canonical/errors__oauth_register_invalid_client_metadata.json new file mode 100644 index 0000000..461c91d --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__oauth_register_invalid_client_metadata.json @@ -0,0 +1,12 @@ +{ + "status": 400, + "body": { + "error": "invalid_client_metadata", + "error_description": "token_endpoint_auth_method must be none: Lenz registers public clients that use PKCE." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__oauth_register_invalid_redirect_uri.json b/tests/fixtures/parity/canonical/errors__oauth_register_invalid_redirect_uri.json new file mode 100644 index 0000000..63e62ba --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__oauth_register_invalid_redirect_uri.json @@ -0,0 +1,12 @@ +{ + "status": 400, + "body": { + "error": "invalid_redirect_uri", + "error_description": "Each redirect URI must be https, or http on localhost, 127.0.0.1 or [::1], without a fragment." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__oauth_revoke_invalid_client.json b/tests/fixtures/parity/canonical/errors__oauth_revoke_invalid_client.json new file mode 100644 index 0000000..a7a70ef --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__oauth_revoke_invalid_client.json @@ -0,0 +1,13 @@ +{ + "status": 401, + "body": { + "error": "invalid_client", + "error_description": "Client authentication failed." + }, + "headers": { + "Content-Type": "application/json", + "WWW-Authenticate": "Basic realm=\"lenz\"", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__oauth_token_invalid_client.json b/tests/fixtures/parity/canonical/errors__oauth_token_invalid_client.json new file mode 100644 index 0000000..a7a70ef --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__oauth_token_invalid_client.json @@ -0,0 +1,13 @@ +{ + "status": 401, + "body": { + "error": "invalid_client", + "error_description": "Client authentication failed." + }, + "headers": { + "Content-Type": "application/json", + "WWW-Authenticate": "Basic realm=\"lenz\"", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__oauth_token_invalid_grant.json b/tests/fixtures/parity/canonical/errors__oauth_token_invalid_grant.json new file mode 100644 index 0000000..88c6f64 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__oauth_token_invalid_grant.json @@ -0,0 +1,12 @@ +{ + "status": 400, + "body": { + "error": "invalid_grant", + "error_description": "The authorization is invalid or has expired." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__oauth_token_missing_grant_type.json b/tests/fixtures/parity/canonical/errors__oauth_token_missing_grant_type.json new file mode 100644 index 0000000..f989e00 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__oauth_token_missing_grant_type.json @@ -0,0 +1,11 @@ +{ + "status": 400, + "body": { + "error": "unsupported_grant_type" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__oauth_token_refresh_invalid_grant.json b/tests/fixtures/parity/canonical/errors__oauth_token_refresh_invalid_grant.json new file mode 100644 index 0000000..88c6f64 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__oauth_token_refresh_invalid_grant.json @@ -0,0 +1,12 @@ +{ + "status": 400, + "body": { + "error": "invalid_grant", + "error_description": "The authorization is invalid or has expired." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__oauth_token_unsupported_grant_type.json b/tests/fixtures/parity/canonical/errors__oauth_token_unsupported_grant_type.json new file mode 100644 index 0000000..f989e00 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__oauth_token_unsupported_grant_type.json @@ -0,0 +1,11 @@ +{ + "status": 400, + "body": { + "error": "unsupported_grant_type" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/errors__payment_required_ask.json b/tests/fixtures/parity/canonical/errors__payment_required_ask.json index e4bc4cf..72c49cc 100644 --- a/tests/fixtures/parity/canonical/errors__payment_required_ask.json +++ b/tests/fixtures/parity/canonical/errors__payment_required_ask.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining ask credits.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__payment_required_assess.json b/tests/fixtures/parity/canonical/errors__payment_required_assess.json index 5e931cc..c64d322 100644 --- a/tests/fixtures/parity/canonical/errors__payment_required_assess.json +++ b/tests/fixtures/parity/canonical/errors__payment_required_assess.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining /assess units.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__payment_required_verify.json b/tests/fixtures/parity/canonical/errors__payment_required_verify.json index 1f73a67..d93b382 100644 --- a/tests/fixtures/parity/canonical/errors__payment_required_verify.json +++ b/tests/fixtures/parity/canonical/errors__payment_required_verify.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining claim checks.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 10 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__payment_required_verify_batch_short.json b/tests/fixtures/parity/canonical/errors__payment_required_verify_batch_short.json index e80d840..45ee9f8 100644 --- a/tests/fixtures/parity/canonical/errors__payment_required_verify_batch_short.json +++ b/tests/fixtures/parity/canonical/errors__payment_required_verify_batch_short.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Insufficient credits for batch.", "code": "no_credits", @@ -13,8 +8,13 @@ "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "requested": 5, "remaining": 3, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 30, "cost": 50 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__rate_limited_extract.json b/tests/fixtures/parity/canonical/errors__rate_limited_extract.json index e45b708..35f093a 100644 --- a/tests/fixtures/parity/canonical/errors__rate_limited_extract.json +++ b/tests/fixtures/parity/canonical/errors__rate_limited_extract.json @@ -1,11 +1,5 @@ { "status": 429, - "headers": { - "Content-Type": "application/json", - "Retry-After": "900", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", "code": "extract_daily_limit", @@ -13,5 +7,11 @@ "retry_after": 900, "docs_url": "https://lenz.io/docs/errors#rate-limits", "upgrade_url": "https://lenz.io/plans" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "900", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__service_unavailable_ask.json b/tests/fixtures/parity/canonical/errors__service_unavailable_ask.json index 94a09cd..baaa646 100644 --- a/tests/fixtures/parity/canonical/errors__service_unavailable_ask.json +++ b/tests/fixtures/parity/canonical/errors__service_unavailable_ask.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "The chat model is unavailable right now. Retry shortly.", "code": "upstream_unavailable", "retry_after": 90, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__service_unavailable_capacity.json b/tests/fixtures/parity/canonical/errors__service_unavailable_capacity.json index cc8fad8..036bd5a 100644 --- a/tests/fixtures/parity/canonical/errors__service_unavailable_capacity.json +++ b/tests/fixtures/parity/canonical/errors__service_unavailable_capacity.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "60", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": 60, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__validation_malformed_json.json b/tests/fixtures/parity/canonical/errors__validation_malformed_json.json index 9e1f37c..23ac8ec 100644 --- a/tests/fixtures/parity/canonical/errors__validation_malformed_json.json +++ b/tests/fixtures/parity/canonical/errors__validation_malformed_json.json @@ -1,12 +1,12 @@ { "status": 400, + "body": { + "detail": "The request body is not valid JSON.", + "code": "malformed_body" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "The request body is not valid JSON.", - "code": "malformed_body" } } diff --git a/tests/fixtures/parity/canonical/errors__validation_missing_field_hint.json b/tests/fixtures/parity/canonical/errors__validation_missing_field_hint.json index 2cf69f1..a4831ce 100644 --- a/tests/fixtures/parity/canonical/errors__validation_missing_field_hint.json +++ b/tests/fixtures/parity/canonical/errors__validation_missing_field_hint.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "text: Field required", "code": "validation_error", @@ -25,5 +20,10 @@ "content", "bogus" ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__validation_unknown_field_only.json b/tests/fixtures/parity/canonical/errors__validation_unknown_field_only.json index 877dab6..381ab3e 100644 --- a/tests/fixtures/parity/canonical/errors__validation_unknown_field_only.json +++ b/tests/fixtures/parity/canonical/errors__validation_unknown_field_only.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claim: Field required", "code": "validation_error", @@ -24,5 +19,10 @@ "unrecognized_fields": [ "statement" ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__validation_unknown_field_wrong_type.json b/tests/fixtures/parity/canonical/errors__validation_unknown_field_wrong_type.json index 1aae12f..751ca61 100644 --- a/tests/fixtures/parity/canonical/errors__validation_unknown_field_wrong_type.json +++ b/tests/fixtures/parity/canonical/errors__validation_unknown_field_wrong_type.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claims: Input should be a valid list", "code": "validation_error", @@ -23,5 +18,10 @@ "bogus_field", "another" ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__validation_wrong_type.json b/tests/fixtures/parity/canonical/errors__validation_wrong_type.json index 843bab6..7f77b76 100644 --- a/tests/fixtures/parity/canonical/errors__validation_wrong_type.json +++ b/tests/fixtures/parity/canonical/errors__validation_wrong_type.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "text: Input should be a valid string", "code": "validation_error", @@ -19,5 +14,10 @@ "type": "string_type" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/errors__web_assess_payment_required.json b/tests/fixtures/parity/canonical/errors__web_assess_payment_required.json new file mode 100644 index 0000000..5e8991b --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__web_assess_payment_required.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "body": { + "detail": "No assessments left this month.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T14:07:00+00:00", + "credits_remaining": 0, + "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "Cookie" + } +} diff --git a/tests/fixtures/parity/canonical/errors__web_assess_signup_required.json b/tests/fixtures/parity/canonical/errors__web_assess_signup_required.json new file mode 100644 index 0000000..7621cf2 --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__web_assess_signup_required.json @@ -0,0 +1,14 @@ +{ + "status": 403, + "body": { + "detail": "Sign up to check this — it’s free.", + "code": "signup_required", + "signup_claim_stashed": false, + "attempt": "e2fffcdbaf5c6cfc1939f3eaec689a87" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "Cookie" + } +} diff --git a/tests/fixtures/parity/canonical/errors__web_review_rate_limited.json b/tests/fixtures/parity/canonical/errors__web_review_rate_limited.json new file mode 100644 index 0000000..0e7609f --- /dev/null +++ b/tests/fixtures/parity/canonical/errors__web_review_rate_limited.json @@ -0,0 +1,17 @@ +{ + "status": 429, + "body": { + "detail": "This account has used its extractions for today. The daily allowance is shared with the Lenz API. It resets at 00:00 UTC.", + "code": "extract_daily_limit", + "limit": 1000, + "reset_in_seconds": 777, + "doc_url": "https://lenz.io/docs/errors#rate-limits", + "upgrade_url": "https://lenz.io/plans" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "777", + "Cache-Control": "no-store", + "Vary": "Cookie" + } +} diff --git a/tests/fixtures/parity/canonical/extract__401_no_key.json b/tests/fixtures/parity/canonical/extract__401_no_key.json index 1c3df51..dcdaad0 100644 --- a/tests/fixtures/parity/canonical/extract__401_no_key.json +++ b/tests/fixtures/parity/canonical/extract__401_no_key.json @@ -1,12 +1,12 @@ { "status": 401, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized", - "code": "not_authenticated" } } diff --git a/tests/fixtures/parity/canonical/extract__422_blank_text.json b/tests/fixtures/parity/canonical/extract__422_blank_text.json index 4242aac..9111f0b 100644 --- a/tests/fixtures/parity/canonical/extract__422_blank_text.json +++ b/tests/fixtures/parity/canonical/extract__422_blank_text.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Text is required.", "code": "blank_input", @@ -18,5 +13,10 @@ "type": "blank_input" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__422_focus_too_long.json b/tests/fixtures/parity/canonical/extract__422_focus_too_long.json index 6645b81..228a79f 100644 --- a/tests/fixtures/parity/canonical/extract__422_focus_too_long.json +++ b/tests/fixtures/parity/canonical/extract__422_focus_too_long.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "focus must be at most 300 characters of plain text.", "code": "validation_error", @@ -18,5 +13,10 @@ "type": "validation_error" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__422_missing_text.json b/tests/fixtures/parity/canonical/extract__422_missing_text.json index eb7b0fc..9ce0a7d 100644 --- a/tests/fixtures/parity/canonical/extract__422_missing_text.json +++ b/tests/fixtures/parity/canonical/extract__422_missing_text.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "text: Field required", "code": "validation_error", @@ -19,5 +14,10 @@ "type": "missing" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__429_daily_limit.json b/tests/fixtures/parity/canonical/extract__429_daily_limit.json index 23ae05b..7ed31f0 100644 --- a/tests/fixtures/parity/canonical/extract__429_daily_limit.json +++ b/tests/fixtures/parity/canonical/extract__429_daily_limit.json @@ -1,11 +1,5 @@ { "status": 429, - "headers": { - "Content-Type": "application/json", - "Retry-After": "3600", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", "code": "extract_daily_limit", @@ -13,5 +7,11 @@ "retry_after": 3600, "docs_url": "https://lenz.io/docs/errors#rate-limits", "upgrade_url": "https://lenz.io/plans" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "3600", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__502_extraction_failed.json b/tests/fixtures/parity/canonical/extract__502_extraction_failed.json index 62f2e63..645e6f6 100644 --- a/tests/fixtures/parity/canonical/extract__502_extraction_failed.json +++ b/tests/fixtures/parity/canonical/extract__502_extraction_failed.json @@ -1,12 +1,12 @@ { "status": 502, + "body": { + "detail": "Extraction failed", + "code": "extraction_failed" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Extraction failed", - "code": "extraction_failed" } } diff --git a/tests/fixtures/parity/canonical/extract__503_upstream_unavailable.json b/tests/fixtures/parity/canonical/extract__503_upstream_unavailable.json index 3315806..be8c7a9 100644 --- a/tests/fixtures/parity/canonical/extract__503_upstream_unavailable.json +++ b/tests/fixtures/parity/canonical/extract__503_upstream_unavailable.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Our model providers are temporarily unavailable. Please retry shortly.", "code": "upstream_unavailable", "retry_after": 90, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__focus_ready.json b/tests/fixtures/parity/canonical/extract__focus_ready.json index 29eccf2..6229973 100644 --- a/tests/fixtures/parity/canonical/extract__focus_ready.json +++ b/tests/fixtures/parity/canonical/extract__focus_ready.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claims": [ @@ -26,5 +21,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__idempotency_body_mismatch_422.json b/tests/fixtures/parity/canonical/extract__idempotency_body_mismatch_422.json index e20089e..8cdd4be 100644 --- a/tests/fixtures/parity/canonical/extract__idempotency_body_mismatch_422.json +++ b/tests/fixtures/parity/canonical/extract__idempotency_body_mismatch_422.json @@ -1,12 +1,12 @@ { "status": 422, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Idempotency-Key reused with a different request body.", - "code": "idempotency_body_mismatch" } } diff --git a/tests/fixtures/parity/canonical/extract__idempotency_replay.json b/tests/fixtures/parity/canonical/extract__idempotency_replay.json index b508889..d1b6b07 100644 --- a/tests/fixtures/parity/canonical/extract__idempotency_replay.json +++ b/tests/fixtures/parity/canonical/extract__idempotency_replay.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claims": [ @@ -30,5 +25,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__locate_all_dropped.json b/tests/fixtures/parity/canonical/extract__locate_all_dropped.json index 7906518..2886061 100644 --- a/tests/fixtures/parity/canonical/extract__locate_all_dropped.json +++ b/tests/fixtures/parity/canonical/extract__locate_all_dropped.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "no_checkable_claim", "claims": [], @@ -21,5 +16,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__locate_failed.json b/tests/fixtures/parity/canonical/extract__locate_failed.json index 2fbe6a7..a4ce206 100644 --- a/tests/fixtures/parity/canonical/extract__locate_failed.json +++ b/tests/fixtures/parity/canonical/extract__locate_failed.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claims": [ @@ -30,5 +25,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__locate_leading_whitespace.json b/tests/fixtures/parity/canonical/extract__locate_leading_whitespace.json index 8033e2d..a84de40 100644 --- a/tests/fixtures/parity/canonical/extract__locate_leading_whitespace.json +++ b/tests/fixtures/parity/canonical/extract__locate_leading_whitespace.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claims": [ @@ -32,5 +27,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__locate_some_dropped.json b/tests/fixtures/parity/canonical/extract__locate_some_dropped.json index 11529fa..15e296a 100644 --- a/tests/fixtures/parity/canonical/extract__locate_some_dropped.json +++ b/tests/fixtures/parity/canonical/extract__locate_some_dropped.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claims": [ @@ -42,5 +37,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__locate_true.json b/tests/fixtures/parity/canonical/extract__locate_true.json index 11529fa..15e296a 100644 --- a/tests/fixtures/parity/canonical/extract__locate_true.json +++ b/tests/fixtures/parity/canonical/extract__locate_true.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claims": [ @@ -42,5 +37,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__no_match_with_focus.json b/tests/fixtures/parity/canonical/extract__no_match_with_focus.json index eceaf0b..b3a7571 100644 --- a/tests/fixtures/parity/canonical/extract__no_match_with_focus.json +++ b/tests/fixtures/parity/canonical/extract__no_match_with_focus.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "no_match", "claims": [], @@ -12,5 +7,10 @@ "key_entities": [], "presumed_intent": "", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__not_a_claim.json b/tests/fixtures/parity/canonical/extract__not_a_claim.json index df06a66..25e526b 100644 --- a/tests/fixtures/parity/canonical/extract__not_a_claim.json +++ b/tests/fixtures/parity/canonical/extract__not_a_claim.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "no_checkable_claim", "claims": [], @@ -12,5 +7,10 @@ "key_entities": [], "presumed_intent": "", "original_input": "What a lovely day." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__not_a_claim_beside_claims.json b/tests/fixtures/parity/canonical/extract__not_a_claim_beside_claims.json index 646bbad..a0569d2 100644 --- a/tests/fixtures/parity/canonical/extract__not_a_claim_beside_claims.json +++ b/tests/fixtures/parity/canonical/extract__not_a_claim_beside_claims.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claims": [ @@ -26,5 +21,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__ready_one_claim.json b/tests/fixtures/parity/canonical/extract__ready_one_claim.json index 646bbad..a0569d2 100644 --- a/tests/fixtures/parity/canonical/extract__ready_one_claim.json +++ b/tests/fixtures/parity/canonical/extract__ready_one_claim.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claims": [ @@ -26,5 +21,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__ready_several_claims.json b/tests/fixtures/parity/canonical/extract__ready_several_claims.json index 2fbe6a7..a4ce206 100644 --- a/tests/fixtures/parity/canonical/extract__ready_several_claims.json +++ b/tests/fixtures/parity/canonical/extract__ready_several_claims.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claims": [ @@ -30,5 +25,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__replay_later_200.json b/tests/fixtures/parity/canonical/extract__replay_later_200.json index 8fff1c2..8f23ae8 100644 --- a/tests/fixtures/parity/canonical/extract__replay_later_200.json +++ b/tests/fixtures/parity/canonical/extract__replay_later_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Alpha rose 5% in 2024.", @@ -27,5 +22,10 @@ "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", "locations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__url_fetch_502_unreadable.json b/tests/fixtures/parity/canonical/extract__url_fetch_502_unreadable.json index 62f2e63..645e6f6 100644 --- a/tests/fixtures/parity/canonical/extract__url_fetch_502_unreadable.json +++ b/tests/fixtures/parity/canonical/extract__url_fetch_502_unreadable.json @@ -1,12 +1,12 @@ { "status": 502, + "body": { + "detail": "Extraction failed", + "code": "extraction_failed" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Extraction failed", - "code": "extraction_failed" } } diff --git a/tests/fixtures/parity/canonical/extract__url_fetch_503_upstream.json b/tests/fixtures/parity/canonical/extract__url_fetch_503_upstream.json index 14eded6..182b135 100644 --- a/tests/fixtures/parity/canonical/extract__url_fetch_503_upstream.json +++ b/tests/fixtures/parity/canonical/extract__url_fetch_503_upstream.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "The page could not be read right now. Please retry shortly.", "code": "upstream_unavailable", "retry_after": 90, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/extract__url_input_located.json b/tests/fixtures/parity/canonical/extract__url_input_located.json index 5c97376..dbed678 100644 --- a/tests/fixtures/parity/canonical/extract__url_input_located.json +++ b/tests/fixtures/parity/canonical/extract__url_input_located.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claims": [ @@ -32,5 +27,10 @@ ], "presumed_intent": "Verify reported figures", "original_input": "https://example.com/an-article" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__401_no_credentials.json b/tests/fixtures/parity/canonical/review__401_no_credentials.json index 1c3df51..dcdaad0 100644 --- a/tests/fixtures/parity/canonical/review__401_no_credentials.json +++ b/tests/fixtures/parity/canonical/review__401_no_credentials.json @@ -1,12 +1,12 @@ { "status": 401, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized", - "code": "not_authenticated" } } diff --git a/tests/fixtures/parity/canonical/review__402_no_credits.json b/tests/fixtures/parity/canonical/review__402_no_credits.json index 5a9f5be..7185c43 100644 --- a/tests/fixtures/parity/canonical/review__402_no_credits.json +++ b/tests/fixtures/parity/canonical/review__402_no_credits.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining credits to assess the draft.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 100, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 100, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__402_no_credits_exhausted.json b/tests/fixtures/parity/canonical/review__402_no_credits_exhausted.json index 2ec177c..543c798 100644 --- a/tests/fixtures/parity/canonical/review__402_no_credits_exhausted.json +++ b/tests/fixtures/parity/canonical/review__402_no_credits_exhausted.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining credits to assess the draft.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_blank_text.json b/tests/fixtures/parity/canonical/review__422_blank_text.json index ee12b17..784e798 100644 --- a/tests/fixtures/parity/canonical/review__422_blank_text.json +++ b/tests/fixtures/parity/canonical/review__422_blank_text.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "text: send the draft, or one public http(s) URL.", "code": "blank_input", @@ -18,5 +13,10 @@ "type": "blank_input" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_citations_options_object.json b/tests/fixtures/parity/canonical/review__422_citations_options_object.json index 8932e84..010e256 100644 --- a/tests/fixtures/parity/canonical/review__422_citations_options_object.json +++ b/tests/fixtures/parity/canonical/review__422_citations_options_object.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "citations: Extra inputs are not permitted", "code": "validation_error", @@ -19,5 +14,10 @@ "type": "extra_forbidden" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_depth_unknown.json b/tests/fixtures/parity/canonical/review__422_depth_unknown.json index 3ef5a12..1bb9ce0 100644 --- a/tests/fixtures/parity/canonical/review__422_depth_unknown.json +++ b/tests/fixtures/parity/canonical/review__422_depth_unknown.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "escalate.depth: Input should be 'standard' or 'low'", "code": "validation_error", @@ -23,5 +18,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_invalid_confidence_band.json b/tests/fixtures/parity/canonical/review__422_invalid_confidence_band.json index 9ece217..41fcbb5 100644 --- a/tests/fixtures/parity/canonical/review__422_invalid_confidence_band.json +++ b/tests/fixtures/parity/canonical/review__422_invalid_confidence_band.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "escalate.confidence: Unknown confidence band 'certain'; use low, medium or high.", "code": "invalid_confidence_band", @@ -23,5 +18,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_invalid_verdict_label.json b/tests/fixtures/parity/canonical/review__422_invalid_verdict_label.json index ea83a57..bb12352 100644 --- a/tests/fixtures/parity/canonical/review__422_invalid_verdict_label.json +++ b/tests/fixtures/parity/canonical/review__422_invalid_verdict_label.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "escalate.verdicts: Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True.", "code": "invalid_verdict_label", @@ -24,5 +19,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_max_assessments_negative.json b/tests/fixtures/parity/canonical/review__422_max_assessments_negative.json index 0bb1242..401ea72 100644 --- a/tests/fixtures/parity/canonical/review__422_max_assessments_negative.json +++ b/tests/fixtures/parity/canonical/review__422_max_assessments_negative.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "escalate.max_assessments: Input should be greater than or equal to 0", "code": "validation_error", @@ -23,5 +18,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_max_citations_negative.json b/tests/fixtures/parity/canonical/review__422_max_citations_negative.json index dd2cde4..ff211d2 100644 --- a/tests/fixtures/parity/canonical/review__422_max_citations_negative.json +++ b/tests/fixtures/parity/canonical/review__422_max_citations_negative.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "escalate.max_citations: Input should be greater than or equal to 0", "code": "validation_error", @@ -23,5 +18,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_max_citations_too_big.json b/tests/fixtures/parity/canonical/review__422_max_citations_too_big.json index 3d8860c..4f44152 100644 --- a/tests/fixtures/parity/canonical/review__422_max_citations_too_big.json +++ b/tests/fixtures/parity/canonical/review__422_max_citations_too_big.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "escalate.max_citations: Input should be less than or equal to 20", "code": "validation_error", @@ -23,5 +18,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_max_verifications_too_big.json b/tests/fixtures/parity/canonical/review__422_max_verifications_too_big.json index cc5e5b1..aabee59 100644 --- a/tests/fixtures/parity/canonical/review__422_max_verifications_too_big.json +++ b/tests/fixtures/parity/canonical/review__422_max_verifications_too_big.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "escalate.max_verifications: Input should be less than or equal to 20", "code": "validation_error", @@ -23,5 +18,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_text_missing.json b/tests/fixtures/parity/canonical/review__422_text_missing.json index eb7b0fc..9ce0a7d 100644 --- a/tests/fixtures/parity/canonical/review__422_text_missing.json +++ b/tests/fixtures/parity/canonical/review__422_text_missing.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "text: Field required", "code": "validation_error", @@ -19,5 +14,10 @@ "type": "missing" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_text_wrong_type.json b/tests/fixtures/parity/canonical/review__422_text_wrong_type.json index 843bab6..7f77b76 100644 --- a/tests/fixtures/parity/canonical/review__422_text_wrong_type.json +++ b/tests/fixtures/parity/canonical/review__422_text_wrong_type.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "text: Input should be a valid string", "code": "validation_error", @@ -19,5 +14,10 @@ "type": "string_type" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_unknown_escalate_field.json b/tests/fixtures/parity/canonical/review__422_unknown_escalate_field.json index 74bc52a..68067d4 100644 --- a/tests/fixtures/parity/canonical/review__422_unknown_escalate_field.json +++ b/tests/fixtures/parity/canonical/review__422_unknown_escalate_field.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "escalate.nope: Extra inputs are not permitted", "code": "validation_error", @@ -20,5 +15,10 @@ "type": "extra_forbidden" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_unknown_top_level_field.json b/tests/fixtures/parity/canonical/review__422_unknown_top_level_field.json index eecb052..50ccb4b 100644 --- a/tests/fixtures/parity/canonical/review__422_unknown_top_level_field.json +++ b/tests/fixtures/parity/canonical/review__422_unknown_top_level_field.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "max_verifications: Extra inputs are not permitted", "code": "validation_error", @@ -19,5 +14,10 @@ "type": "extra_forbidden" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_unsupported_language.json b/tests/fixtures/parity/canonical/review__422_unsupported_language.json index 9382428..8a0ee14 100644 --- a/tests/fixtures/parity/canonical/review__422_unsupported_language.json +++ b/tests/fixtures/parity/canonical/review__422_unsupported_language.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", "code": "unsupported_language", @@ -18,5 +13,10 @@ "type": "unsupported_language" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_visibility_public.json b/tests/fixtures/parity/canonical/review__422_visibility_public.json index 31600c2..f266df2 100644 --- a/tests/fixtures/parity/canonical/review__422_visibility_public.json +++ b/tests/fixtures/parity/canonical/review__422_visibility_public.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "visibility: Input should be 'private' or 'unlisted'", "code": "validation_error", @@ -22,5 +17,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__422_webhook_secret_missing.json b/tests/fixtures/parity/canonical/review__422_webhook_secret_missing.json new file mode 100644 index 0000000..3286c6c --- /dev/null +++ b/tests/fixtures/parity/canonical/review__422_webhook_secret_missing.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "body": { + "detail": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "code": "webhook_secret_missing", + "errors": [ + { + "loc": [ + "body", + "webhook_url" + ], + "msg": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "type": "webhook_secret_missing" + } + ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/review__429_extract_daily_limit.json b/tests/fixtures/parity/canonical/review__429_extract_daily_limit.json index 320069f..7ea7dc9 100644 --- a/tests/fixtures/parity/canonical/review__429_extract_daily_limit.json +++ b/tests/fixtures/parity/canonical/review__429_extract_daily_limit.json @@ -1,11 +1,5 @@ { "status": 429, - "headers": { - "Content-Type": "application/json", - "Retry-After": "60", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Daily /extract limit of 1000 reached for this account. A review of a URL reads the page like /extract and counts as one /extract call.", "code": "extract_daily_limit", @@ -13,5 +7,11 @@ "retry_after": 60, "docs_url": "https://lenz.io/docs/errors#rate-limits", "upgrade_url": "https://lenz.io/plans" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__429_review_in_flight.json b/tests/fixtures/parity/canonical/review__429_review_in_flight.json index 61295d1..906f29c 100644 --- a/tests/fixtures/parity/canonical/review__429_review_in_flight.json +++ b/tests/fixtures/parity/canonical/review__429_review_in_flight.json @@ -1,14 +1,14 @@ { "status": 429, + "body": { + "detail": "This account already has 3 reviews running. Retry when one completes.", + "code": "review_in_flight", + "retry_after": 60 + }, "headers": { "Content-Type": "application/json", "Retry-After": "60", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "This account already has 3 reviews running. Retry when one completes.", - "code": "review_in_flight", - "retry_after": 60 } } diff --git a/tests/fixtures/parity/canonical/review__503_capacity.json b/tests/fixtures/parity/canonical/review__503_capacity.json index bcff7db..63b5d1c 100644 --- a/tests/fixtures/parity/canonical/review__503_capacity.json +++ b/tests/fixtures/parity/canonical/review__503_capacity.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": 90, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__503_citations_capacity.json b/tests/fixtures/parity/canonical/review__503_citations_capacity.json index bcff7db..63b5d1c 100644 --- a/tests/fixtures/parity/canonical/review__503_citations_capacity.json +++ b/tests/fixtures/parity/canonical/review__503_citations_capacity.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": 90, "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__delete_not_a_route.json b/tests/fixtures/parity/canonical/review__delete_not_a_route.json new file mode 100644 index 0000000..7b3ec88 --- /dev/null +++ b/tests/fixtures/parity/canonical/review__delete_not_a_route.json @@ -0,0 +1,12 @@ +{ + "status": 405, + "body": { + "detail": "Method not allowed.", + "code": "method_not_allowed" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/review__get_403_insufficient_scope.json b/tests/fixtures/parity/canonical/review__get_403_insufficient_scope.json index 80c529c..b6b8f4f 100644 --- a/tests/fixtures/parity/canonical/review__get_403_insufficient_scope.json +++ b/tests/fixtures/parity/canonical/review__get_403_insufficient_scope.json @@ -1,14 +1,14 @@ { "status": 403, + "body": { + "detail": "The access token does not allow this call.", + "code": "insufficient_scope", + "scope": "history:read" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "WWW-Authenticate": "Bearer error=\"insufficient_scope\", scope=\"history:read\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "The access token does not allow this call.", - "code": "insufficient_scope", - "scope": "history:read" } } diff --git a/tests/fixtures/parity/canonical/review__get_404_not_found.json b/tests/fixtures/parity/canonical/review__get_404_not_found.json index 8045cd8..e73d347 100644 --- a/tests/fixtures/parity/canonical/review__get_404_not_found.json +++ b/tests/fixtures/parity/canonical/review__get_404_not_found.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Review not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Review not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/review__get_404_other_account.json b/tests/fixtures/parity/canonical/review__get_404_other_account.json index 8045cd8..e73d347 100644 --- a/tests/fixtures/parity/canonical/review__get_404_other_account.json +++ b/tests/fixtures/parity/canonical/review__get_404_other_account.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Review not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Review not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/review__get_410_purged.json b/tests/fixtures/parity/canonical/review__get_410_purged.json index bedf6a5..396b15a 100644 --- a/tests/fixtures/parity/canonical/review__get_410_purged.json +++ b/tests/fixtures/parity/canonical/review__get_410_purged.json @@ -1,13 +1,13 @@ { "status": 410, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This review is no longer available: its account removes content after a set period.", "code": "purged", "purged_at": "2026-10-01T09:07:00.123456Z" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_422_unknown_view.json b/tests/fixtures/parity/canonical/review__get_422_unknown_view.json index a9df405..70ef8e8 100644 --- a/tests/fixtures/parity/canonical/review__get_422_unknown_view.json +++ b/tests/fixtures/parity/canonical/review__get_422_unknown_view.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "view: use full or issues.", "code": "validation_error", @@ -18,5 +13,10 @@ "type": "validation_error" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_assessing.json b/tests/fixtures/parity/canonical/review__get_assessing.json index 1b8bc1d..d43f14f 100644 --- a/tests/fixtures/parity/canonical/review__get_assessing.json +++ b/tests/fixtures/parity/canonical/review__get_assessing.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "assessing", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -103,5 +98,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_assessment_rows_full_fields.json b/tests/fixtures/parity/canonical/review__get_assessment_rows_full_fields.json index 8680925..6b80bb6 100644 --- a/tests/fixtures/parity/canonical/review__get_assessment_rows_full_fields.json +++ b/tests/fixtures/parity/canonical/review__get_assessment_rows_full_fields.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -165,5 +160,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_clean.json b/tests/fixtures/parity/canonical/review__get_citations_clean.json index 332658b..1b3c2fa 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_clean.json +++ b/tests/fixtures/parity/canonical/review__get_citations_clean.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -178,5 +173,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_failed_and_unchecked.json b/tests/fixtures/parity/canonical/review__get_citations_failed_and_unchecked.json index b180507..37a0c3c 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_failed_and_unchecked.json +++ b/tests/fixtures/parity/canonical/review__get_citations_failed_and_unchecked.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -196,5 +191,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_issue_full.json b/tests/fixtures/parity/canonical/review__get_citations_issue_full.json index b3243d6..a1f8a3d 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_issue_full.json +++ b/tests/fixtures/parity/canonical/review__get_citations_issue_full.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -200,5 +195,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_issue_issues_view.json b/tests/fixtures/parity/canonical/review__get_citations_issue_issues_view.json index 9f60f10..a0c4e66 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_issue_issues_view.json +++ b/tests/fixtures/parity/canonical/review__get_citations_issue_issues_view.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "issues", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -90,5 +85,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_limit_exactly_at_limit.json b/tests/fixtures/parity/canonical/review__get_citations_limit_exactly_at_limit.json index a81b16f..2ea4bba 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_limit_exactly_at_limit.json +++ b/tests/fixtures/parity/canonical/review__get_citations_limit_exactly_at_limit.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -178,5 +173,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_limit_reached.json b/tests/fixtures/parity/canonical/review__get_citations_limit_reached.json index 33eeb1b..2c9db6a 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_limit_reached.json +++ b/tests/fixtures/parity/canonical/review__get_citations_limit_reached.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -152,5 +147,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_no_claim_but_citations.json b/tests/fixtures/parity/canonical/review__get_citations_no_claim_but_citations.json index fbb5a29..d0e9582 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_no_claim_but_citations.json +++ b/tests/fixtures/parity/canonical/review__get_citations_no_claim_but_citations.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -149,5 +144,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_no_claim_no_citation.json b/tests/fixtures/parity/canonical/review__get_citations_no_claim_no_citation.json index e9cdd01..651f5ec 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_no_claim_no_citation.json +++ b/tests/fixtures/parity/canonical/review__get_citations_no_claim_no_citation.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -66,5 +61,10 @@ "more_claims": null, "more_claim_locations": null, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_not_asked.json b/tests/fixtures/parity/canonical/review__get_citations_not_asked.json index 27d5c36..4c5445d 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_not_asked.json +++ b/tests/fixtures/parity/canonical/review__get_citations_not_asked.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -95,5 +90,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_only.json b/tests/fixtures/parity/canonical/review__get_citations_only.json index 4a86304..f642ad3 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_only.json +++ b/tests/fixtures/parity/canonical/review__get_citations_only.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -156,5 +151,10 @@ } ], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_partly_supported.json b/tests/fixtures/parity/canonical/review__get_citations_partly_supported.json index 44488cd..90d39af 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_partly_supported.json +++ b/tests/fixtures/parity/canonical/review__get_citations_partly_supported.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -178,5 +173,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_running.json b/tests/fixtures/parity/canonical/review__get_citations_running.json index ff45b91..65040d3 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_running.json +++ b/tests/fixtures/parity/canonical/review__get_citations_running.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "verifying", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -162,5 +157,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_skipped_switched_off.json b/tests/fixtures/parity/canonical/review__get_citations_skipped_switched_off.json index acfa95b..d7c7c4a 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_skipped_switched_off.json +++ b/tests/fixtures/parity/canonical/review__get_citations_skipped_switched_off.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -95,5 +90,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_citations_skipped_url_input.json b/tests/fixtures/parity/canonical/review__get_citations_skipped_url_input.json index 5919306..4cd763c 100644 --- a/tests/fixtures/parity/canonical/review__get_citations_skipped_url_input.json +++ b/tests/fixtures/parity/canonical/review__get_citations_skipped_url_input.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -66,5 +61,10 @@ "more_claims": null, "more_claim_locations": null, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_claim_limit_not_reached.json b/tests/fixtures/parity/canonical/review__get_claim_limit_not_reached.json index 548c3c8..1e92f55 100644 --- a/tests/fixtures/parity/canonical/review__get_claim_limit_not_reached.json +++ b/tests/fixtures/parity/canonical/review__get_claim_limit_not_reached.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -123,5 +118,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_claim_limit_reached_exact.json b/tests/fixtures/parity/canonical/review__get_claim_limit_reached_exact.json index 6432f12..1d1c6fc 100644 --- a/tests/fixtures/parity/canonical/review__get_claim_limit_reached_exact.json +++ b/tests/fixtures/parity/canonical/review__get_claim_limit_reached_exact.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -123,5 +118,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_completed_assess_only.json b/tests/fixtures/parity/canonical/review__get_completed_assess_only.json index 107ee44..2f25c1e 100644 --- a/tests/fixtures/parity/canonical/review__get_completed_assess_only.json +++ b/tests/fixtures/parity/canonical/review__get_completed_assess_only.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -149,5 +144,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_completed_clean.json b/tests/fixtures/parity/canonical/review__get_completed_clean.json index 0849314..3bf1368 100644 --- a/tests/fixtures/parity/canonical/review__get_completed_clean.json +++ b/tests/fixtures/parity/canonical/review__get_completed_clean.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -123,5 +118,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_completed_issues_all_verified.json b/tests/fixtures/parity/canonical/review__get_completed_issues_all_verified.json index 1b82d0e..015cbce 100644 --- a/tests/fixtures/parity/canonical/review__get_completed_issues_all_verified.json +++ b/tests/fixtures/parity/canonical/review__get_completed_issues_all_verified.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -64,10 +59,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -87,10 +82,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b79019e4", + "verification_id": "4d44dfaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", - "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "verification_url": "https://lenz.io/api/v1/verifications/4d44dfaf", + "url": "https://lenz.io/c/the-earth-is-round-4d44dfaf", "escalation": { "matched_rules": [ "verdict" @@ -138,8 +133,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "c010dca9a43543f518e49f4ec7842ceb", - "verification_id": "b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The EU AI Act took effect in March 2024.", "language": "en", "visibility": "private", @@ -155,10 +150,10 @@ "warnings": [ "w1" ], - "created_at": "2026-10-01T09:49:00.123456+00:00", - "completed_at": "2026-10-01T09:56:00.123456+00:00", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": null @@ -193,8 +188,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "4e02e88b137711f18ba7758af5c40837", - "verification_id": "b79019e4", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "verification_id": "4d44dfaf", "claim": "The Eiffel Tower is in Berlin.", "language": "en", "visibility": "private", @@ -210,10 +205,10 @@ "warnings": [ "w1" ], - "created_at": "2026-10-01T09:49:00.123456+00:00", - "completed_at": "2026-10-01T09:56:00.123456+00:00", - "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", - "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/4d44dfaf", + "url": "https://lenz.io/c/the-earth-is-round-4d44dfaf", "failure": null }, "suggested_edits": null @@ -252,5 +247,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_completed_issues_full.json b/tests/fixtures/parity/canonical/review__get_completed_issues_full.json index ff3d65d..4e497ee 100644 --- a/tests/fixtures/parity/canonical/review__get_completed_issues_full.json +++ b/tests/fixtures/parity/canonical/review__get_completed_issues_full.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -64,10 +59,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -159,8 +154,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "7df4009bc27aab64ce5d5a01fbafe599", - "verification_id": "b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The EU AI Act took effect in March 2024.", "language": "en", "visibility": "private", @@ -176,10 +171,10 @@ "warnings": [ "w1" ], - "created_at": "2026-10-01T09:42:00.123456+00:00", - "completed_at": "2026-10-01T09:49:00.123456+00:00", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": null @@ -240,7 +235,7 @@ }, "verification": { "verification_id": null, - "task_id": "4634b89821fd877f1edf8aaeb82b7ee5", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", "claim": null, "language": null, "visibility": null, @@ -305,5 +300,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_completed_issues_view_issues.json b/tests/fixtures/parity/canonical/review__get_completed_issues_view_issues.json index a136287..73cb5d3 100644 --- a/tests/fixtures/parity/canonical/review__get_completed_issues_view_issues.json +++ b/tests/fixtures/parity/canonical/review__get_completed_issues_view_issues.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "issues", "status": "completed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -64,10 +59,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -132,5 +127,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_completed_positions.json b/tests/fixtures/parity/canonical/review__get_completed_positions.json index 7a3c9e1..94542c7 100644 --- a/tests/fixtures/parity/canonical/review__get_completed_positions.json +++ b/tests/fixtures/parity/canonical/review__get_completed_positions.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -135,5 +130,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_completed_recovered_claim.json b/tests/fixtures/parity/canonical/review__get_completed_recovered_claim.json index aafdbe0..00ba6b6 100644 --- a/tests/fixtures/parity/canonical/review__get_completed_recovered_claim.json +++ b/tests/fixtures/parity/canonical/review__get_completed_recovered_claim.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -95,5 +90,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_completed_with_untraced_claim.json b/tests/fixtures/parity/canonical/review__get_completed_with_untraced_claim.json index 64ad9f0..39a95cd 100644 --- a/tests/fixtures/parity/canonical/review__get_completed_with_untraced_claim.json +++ b/tests/fixtures/parity/canonical/review__get_completed_with_untraced_claim.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -135,5 +130,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_during_quick_check.json b/tests/fixtures/parity/canonical/review__get_during_quick_check.json index 06f27e1..ecff88a 100644 --- a/tests/fixtures/parity/canonical/review__get_during_quick_check.json +++ b/tests/fixtures/parity/canonical/review__get_during_quick_check.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "assessing", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -83,5 +78,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_failed_every_assessment_failed.json b/tests/fixtures/parity/canonical/review__get_failed_every_assessment_failed.json index 93ea710..b66ecb1 100644 --- a/tests/fixtures/parity/canonical/review__get_failed_every_assessment_failed.json +++ b/tests/fixtures/parity/canonical/review__get_failed_every_assessment_failed.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -155,5 +150,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_failed_no_claim.json b/tests/fixtures/parity/canonical/review__get_failed_no_claim.json index d8506ac..a21cf53 100644 --- a/tests/fixtures/parity/canonical/review__get_failed_no_claim.json +++ b/tests/fixtures/parity/canonical/review__get_failed_no_claim.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -66,5 +61,10 @@ "more_claims": null, "more_claim_locations": null, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_failed_no_claim_untraced.json b/tests/fixtures/parity/canonical/review__get_failed_no_claim_untraced.json index 9d2e2ea..776ba8a 100644 --- a/tests/fixtures/parity/canonical/review__get_failed_no_claim_untraced.json +++ b/tests/fixtures/parity/canonical/review__get_failed_no_claim_untraced.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -66,5 +61,10 @@ "more_claims": null, "more_claim_locations": null, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_more_claims.json b/tests/fixtures/parity/canonical/review__get_more_claims.json index ffaacb2..798f568 100644 --- a/tests/fixtures/parity/canonical/review__get_more_claims.json +++ b/tests/fixtures/parity/canonical/review__get_more_claims.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -148,5 +143,10 @@ } ], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json index 62d9316..7f34405 100644 --- a/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -64,10 +59,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -115,8 +110,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "7df4009bc27aab64ce5d5a01fbafe599", - "verification_id": "b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", "language": "en", "visibility": "private", @@ -134,8 +129,8 @@ ], "created_at": "2026-10-01T23:55:00.123456+00:00", "completed_at": "2026-10-02T00:03:00.123456+00:00", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": null @@ -146,5 +141,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_same_day_hours_apart.json index 1aeb435..8295eb7 100644 --- a/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/canonical/review__get_nested_verification_modified_at_same_day_hours_apart.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -64,10 +59,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -115,8 +110,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "7df4009bc27aab64ce5d5a01fbafe599", - "verification_id": "b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", "language": "en", "visibility": "private", @@ -134,8 +129,8 @@ ], "created_at": "2026-10-01T08:00:00.123456+00:00", "completed_at": "2026-10-01T20:00:00.123456+00:00", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": null @@ -146,5 +141,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_policy_resolved.json b/tests/fixtures/parity/canonical/review__get_policy_resolved.json index cc1e568..7d2074b 100644 --- a/tests/fixtures/parity/canonical/review__get_policy_resolved.json +++ b/tests/fixtures/parity/canonical/review__get_policy_resolved.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -93,5 +88,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_queued.json b/tests/fixtures/parity/canonical/review__get_queued.json index 1b08c33..70a4825 100644 --- a/tests/fixtures/parity/canonical/review__get_queued.json +++ b/tests/fixtures/parity/canonical/review__get_queued.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "queued", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -59,5 +54,10 @@ "more_claims": null, "more_claim_locations": null, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_suggested_edits.json b/tests/fixtures/parity/canonical/review__get_suggested_edits.json index 8f4e0a0..0bfdfa3 100644 --- a/tests/fixtures/parity/canonical/review__get_suggested_edits.json +++ b/tests/fixtures/parity/canonical/review__get_suggested_edits.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "verifying", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -64,10 +59,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "7c83247c", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", - "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -158,8 +153,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "9bca1e0819de60a750186e812dc58e2b", - "verification_id": "7c83247c", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", "language": "en", "visibility": "private", @@ -175,10 +170,10 @@ "warnings": [ "w1" ], - "created_at": "2026-10-01T09:35:00.123456+00:00", - "completed_at": "2026-10-01T09:42:00.123456+00:00", - "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", - "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": { @@ -262,5 +257,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_suggested_edits_issues_view.json b/tests/fixtures/parity/canonical/review__get_suggested_edits_issues_view.json index 8914521..5d39a66 100644 --- a/tests/fixtures/parity/canonical/review__get_suggested_edits_issues_view.json +++ b/tests/fixtures/parity/canonical/review__get_suggested_edits_issues_view.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "issues", "status": "verifying", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -64,10 +59,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "7c83247c", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", - "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -125,5 +120,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_url_review.json b/tests/fixtures/parity/canonical/review__get_url_review.json index 90ea98e..9dabe53 100644 --- a/tests/fixtures/parity/canonical/review__get_url_review.json +++ b/tests/fixtures/parity/canonical/review__get_url_review.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -101,5 +96,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__get_verifying.json b/tests/fixtures/parity/canonical/review__get_verifying.json index 1663113..f49c966 100644 --- a/tests/fixtures/parity/canonical/review__get_verifying.json +++ b/tests/fixtures/parity/canonical/review__get_verifying.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "verifying", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -172,5 +167,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__idempotency_body_mismatch_422.json b/tests/fixtures/parity/canonical/review__idempotency_body_mismatch_422.json index e20089e..8cdd4be 100644 --- a/tests/fixtures/parity/canonical/review__idempotency_body_mismatch_422.json +++ b/tests/fixtures/parity/canonical/review__idempotency_body_mismatch_422.json @@ -1,12 +1,12 @@ { "status": 422, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Idempotency-Key reused with a different request body.", - "code": "idempotency_body_mismatch" } } diff --git a/tests/fixtures/parity/canonical/review__idempotency_conflict_409.json b/tests/fixtures/parity/canonical/review__idempotency_conflict_409.json index 8bbdff7..e0a63b2 100644 --- a/tests/fixtures/parity/canonical/review__idempotency_conflict_409.json +++ b/tests/fixtures/parity/canonical/review__idempotency_conflict_409.json @@ -1,13 +1,13 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "A review with this Idempotency-Key is still being created. Retry shortly.", "code": "idempotency_conflict", "review_id": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__idempotency_conflict_409_existing_review.json b/tests/fixtures/parity/canonical/review__idempotency_conflict_409_existing_review.json index edef440..e91fe17 100644 --- a/tests/fixtures/parity/canonical/review__idempotency_conflict_409_existing_review.json +++ b/tests/fixtures/parity/canonical/review__idempotency_conflict_409_existing_review.json @@ -1,13 +1,13 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "A review with this Idempotency-Key is still being created. Retry shortly.", "code": "idempotency_conflict", "review_id": "d6b2bd72" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/review__idempotent_replay_202.json b/tests/fixtures/parity/canonical/review__idempotent_replay_202.json index 6a0872b..ea99cf8 100644 --- a/tests/fixtures/parity/canonical/review__idempotent_replay_202.json +++ b/tests/fixtures/parity/canonical/review__idempotent_replay_202.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/reviews/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "review_id": "d6b2bd72", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/review__receipt_202.json b/tests/fixtures/parity/canonical/review__receipt_202.json index 6a0872b..ea99cf8 100644 --- a/tests/fixtures/parity/canonical/review__receipt_202.json +++ b/tests/fixtures/parity/canonical/review__receipt_202.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/reviews/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "review_id": "d6b2bd72", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/review__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/canonical/review__receipt_202_empty_webhook_url.json index 6a0872b..ea99cf8 100644 --- a/tests/fixtures/parity/canonical/review__receipt_202_empty_webhook_url.json +++ b/tests/fixtures/parity/canonical/review__receipt_202_empty_webhook_url.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/reviews/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "review_id": "d6b2bd72", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/review__receipt_202_webhook_url.json b/tests/fixtures/parity/canonical/review__receipt_202_webhook_url.json index 6a0872b..ea99cf8 100644 --- a/tests/fixtures/parity/canonical/review__receipt_202_webhook_url.json +++ b/tests/fixtures/parity/canonical/review__receipt_202_webhook_url.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/reviews/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "review_id": "d6b2bd72", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/review__replay_later_202.json b/tests/fixtures/parity/canonical/review__replay_later_202.json index 6a0872b..ea99cf8 100644 --- a/tests/fixtures/parity/canonical/review__replay_later_202.json +++ b/tests/fixtures/parity/canonical/review__replay_later_202.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/reviews/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "review_id": "d6b2bd72", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/verify__batch_202.json b/tests/fixtures/parity/canonical/verify__batch_202.json index be544f2..654ab00 100644 --- a/tests/fixtures/parity/canonical/verify__batch_202.json +++ b/tests/fixtures/parity/canonical/verify__batch_202.json @@ -1,21 +1,21 @@ { "status": 202, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "batch_id": "7ea9cdbd4064e3cf", "items": [ { - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "claim": "The Earth is round." }, { - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", "claim": "Water boils at 100C at sea level." } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__batch_capacity_503.json b/tests/fixtures/parity/canonical/verify__batch_capacity_503.json index 2e25ef0..0994e62 100644 --- a/tests/fixtures/parity/canonical/verify__batch_capacity_503.json +++ b/tests/fixtures/parity/canonical/verify__batch_capacity_503.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": "", "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__batch_empty_422.json b/tests/fixtures/parity/canonical/verify__batch_empty_422.json index 0082c60..59dd9ca 100644 --- a/tests/fixtures/parity/canonical/verify__batch_empty_422.json +++ b/tests/fixtures/parity/canonical/verify__batch_empty_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claims is required and must be non-empty.", "code": "validation_error", @@ -18,5 +13,10 @@ "type": "validation_error" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__batch_idempotency_conflict_409.json b/tests/fixtures/parity/canonical/verify__batch_idempotency_conflict_409.json index 788b394..dc881a8 100644 --- a/tests/fixtures/parity/canonical/verify__batch_idempotency_conflict_409.json +++ b/tests/fixtures/parity/canonical/verify__batch_idempotency_conflict_409.json @@ -1,13 +1,13 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "A request with this Idempotency-Key is already in progress.", "code": "idempotency_conflict", "task_id": "7cff18d" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__batch_item_missing_claim_422.json b/tests/fixtures/parity/canonical/verify__batch_item_missing_claim_422.json index 7017bcc..0e736d5 100644 --- a/tests/fixtures/parity/canonical/verify__batch_item_missing_claim_422.json +++ b/tests/fixtures/parity/canonical/verify__batch_item_missing_claim_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claims[1].claim: Field required", "code": "validation_error", @@ -21,5 +16,10 @@ "type": "missing" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__batch_no_credits_402.json b/tests/fixtures/parity/canonical/verify__batch_no_credits_402.json index 8991dc1..216b4ba 100644 --- a/tests/fixtures/parity/canonical/verify__batch_no_credits_402.json +++ b/tests/fixtures/parity/canonical/verify__batch_no_credits_402.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Insufficient credits for batch.", "code": "no_credits", @@ -13,8 +8,13 @@ "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "requested": 1, "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 10 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__batch_partial_202.json b/tests/fixtures/parity/canonical/verify__batch_partial_202.json index 1e3656f..f3bb45d 100644 --- a/tests/fixtures/parity/canonical/verify__batch_partial_202.json +++ b/tests/fixtures/parity/canonical/verify__batch_partial_202.json @@ -1,18 +1,18 @@ { "status": 202, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "batch_id": "7ea9cdbd4064e3cf", "items": [ { - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "claim": "First claim." } ], "partial": true + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__batch_too_many_422.json b/tests/fixtures/parity/canonical/verify__batch_too_many_422.json index 5105df7..b239559 100644 --- a/tests/fixtures/parity/canonical/verify__batch_too_many_422.json +++ b/tests/fixtures/parity/canonical/verify__batch_too_many_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Batch size exceeds maximum of 20.", "code": "too_many_items", @@ -18,5 +13,10 @@ "type": "too_many_items" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__blank_claim_422.json b/tests/fixtures/parity/canonical/verify__blank_claim_422.json index a5a1062..bfcc575 100644 --- a/tests/fixtures/parity/canonical/verify__blank_claim_422.json +++ b/tests/fixtures/parity/canonical/verify__blank_claim_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claim is required.", "code": "blank_input", @@ -18,5 +13,10 @@ "type": "blank_input" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__capacity_503.json b/tests/fixtures/parity/canonical/verify__capacity_503.json index 2e25ef0..0994e62 100644 --- a/tests/fixtures/parity/canonical/verify__capacity_503.json +++ b/tests/fixtures/parity/canonical/verify__capacity_503.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": "", "docs_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__delete_200.json b/tests/fixtures/parity/canonical/verify__delete_200.json new file mode 100644 index 0000000..cddadae --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__delete_200.json @@ -0,0 +1,11 @@ +{ + "status": 200, + "body": { + "ok": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/verify__delete_404.json b/tests/fixtures/parity/canonical/verify__delete_404.json new file mode 100644 index 0000000..775d847 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__delete_404.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "body": { + "detail": "Not found.", + "code": "not_found" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/verify__delete_not_yours_404.json b/tests/fixtures/parity/canonical/verify__delete_not_yours_404.json new file mode 100644 index 0000000..775d847 --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__delete_not_yours_404.json @@ -0,0 +1,12 @@ +{ + "status": 404, + "body": { + "detail": "Not found.", + "code": "not_found" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/verify__idempotency_body_mismatch_422.json b/tests/fixtures/parity/canonical/verify__idempotency_body_mismatch_422.json index e20089e..8cdd4be 100644 --- a/tests/fixtures/parity/canonical/verify__idempotency_body_mismatch_422.json +++ b/tests/fixtures/parity/canonical/verify__idempotency_body_mismatch_422.json @@ -1,12 +1,12 @@ { "status": 422, + "body": { + "detail": "Idempotency-Key reused with a different request body.", + "code": "idempotency_body_mismatch" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Idempotency-Key reused with a different request body.", - "code": "idempotency_body_mismatch" } } diff --git a/tests/fixtures/parity/canonical/verify__idempotency_conflict_409.json b/tests/fixtures/parity/canonical/verify__idempotency_conflict_409.json index 1f8ddf5..87958d2 100644 --- a/tests/fixtures/parity/canonical/verify__idempotency_conflict_409.json +++ b/tests/fixtures/parity/canonical/verify__idempotency_conflict_409.json @@ -1,13 +1,13 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "A request with this Idempotency-Key is already in progress.", "code": "idempotency_conflict", "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__idempotency_key_replay.json b/tests/fixtures/parity/canonical/verify__idempotency_key_replay.json index b510371..d47aeaf 100644 --- a/tests/fixtures/parity/canonical/verify__idempotency_key_replay.json +++ b/tests/fixtures/parity/canonical/verify__idempotency_key_replay.json @@ -1,12 +1,12 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/verify__implicit_dedup_200.json b/tests/fixtures/parity/canonical/verify__implicit_dedup_200.json index b510371..d47aeaf 100644 --- a/tests/fixtures/parity/canonical/verify__implicit_dedup_200.json +++ b/tests/fixtures/parity/canonical/verify__implicit_dedup_200.json @@ -1,12 +1,12 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/verify__implicit_repeat_replay.json b/tests/fixtures/parity/canonical/verify__implicit_repeat_replay.json index b510371..d47aeaf 100644 --- a/tests/fixtures/parity/canonical/verify__implicit_repeat_replay.json +++ b/tests/fixtures/parity/canonical/verify__implicit_repeat_replay.json @@ -1,12 +1,12 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/verify__invalid_depth_422.json b/tests/fixtures/parity/canonical/verify__invalid_depth_422.json index ae4883c..3cf1746 100644 --- a/tests/fixtures/parity/canonical/verify__invalid_depth_422.json +++ b/tests/fixtures/parity/canonical/verify__invalid_depth_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "depth: Input should be 'standard' or 'low'", "code": "validation_error", @@ -22,5 +17,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__invalid_language_422.json b/tests/fixtures/parity/canonical/verify__invalid_language_422.json index 5e82c5f..7025ff2 100644 --- a/tests/fixtures/parity/canonical/verify__invalid_language_422.json +++ b/tests/fixtures/parity/canonical/verify__invalid_language_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Unsupported language 'xx-not-a-language'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", "code": "unsupported_language", @@ -18,5 +13,10 @@ "type": "unsupported_language" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__list_200.json b/tests/fixtures/parity/canonical/verify__list_200.json index 0b7e73b..335daa4 100644 --- a/tests/fixtures/parity/canonical/verify__list_200.json +++ b/tests/fixtures/parity/canonical/verify__list_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -18,12 +13,12 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "language": "en" }, { - "verification_id": "b4e2e99d", + "verification_id": "4d44dfaf", "claim": "The Earth is round.", "domain": "Science", "entities": [], @@ -33,13 +28,18 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:35:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", "language": "en" } ], "total": 2, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__list_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/verify__list_200_modified_at_crosses_midnight_by_minutes.json index 267a53e..ed48dbb 100644 --- a/tests/fixtures/parity/canonical/verify__list_200_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/canonical/verify__list_200_modified_at_crosses_midnight_by_minutes.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -26,5 +21,10 @@ "total": 1, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__list_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/verify__list_200_modified_at_same_day_hours_apart.json index 65e23bc..0c50625 100644 --- a/tests/fixtures/parity/canonical/verify__list_200_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/canonical/verify__list_200_modified_at_same_day_hours_apart.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -26,5 +21,10 @@ "total": 1, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__list_clamped_200.json b/tests/fixtures/parity/canonical/verify__list_clamped_200.json index 3d639d4..c208418 100644 --- a/tests/fixtures/parity/canonical/verify__list_clamped_200.json +++ b/tests/fixtures/parity/canonical/verify__list_clamped_200.json @@ -1,14 +1,14 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [], "total": 0, "page": 1, "page_size": 100 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__list_empty_200.json b/tests/fixtures/parity/canonical/verify__list_empty_200.json index b419316..406be8e 100644 --- a/tests/fixtures/parity/canonical/verify__list_empty_200.json +++ b/tests/fixtures/parity/canonical/verify__list_empty_200.json @@ -1,14 +1,14 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [], "total": 0, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__list_page2_200.json b/tests/fixtures/parity/canonical/verify__list_page2_200.json index f83290d..6008819 100644 --- a/tests/fixtures/parity/canonical/verify__list_page2_200.json +++ b/tests/fixtures/parity/canonical/verify__list_page2_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -18,13 +13,18 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "language": "en" } ], "total": 3, "page": 2, "page_size": 2 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__misnamed_field_422.json b/tests/fixtures/parity/canonical/verify__misnamed_field_422.json index 877dab6..381ab3e 100644 --- a/tests/fixtures/parity/canonical/verify__misnamed_field_422.json +++ b/tests/fixtures/parity/canonical/verify__misnamed_field_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claim: Field required", "code": "validation_error", @@ -24,5 +19,10 @@ "unrecognized_fields": [ "statement" ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__missing_claim_422.json b/tests/fixtures/parity/canonical/verify__missing_claim_422.json index 9136471..f5b9868 100644 --- a/tests/fixtures/parity/canonical/verify__missing_claim_422.json +++ b/tests/fixtures/parity/canonical/verify__missing_claim_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claim: Field required", "code": "validation_error", @@ -19,5 +14,10 @@ "type": "missing" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__no_credits_402.json b/tests/fixtures/parity/canonical/verify__no_credits_402.json index 1f73a67..d93b382 100644 --- a/tests/fixtures/parity/canonical/verify__no_credits_402.json +++ b/tests/fixtures/parity/canonical/verify__no_credits_402.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining claim checks.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 10 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__replay_later_202.json b/tests/fixtures/parity/canonical/verify__replay_later_202.json index b6dbf5e..1991e8a 100644 --- a/tests/fixtures/parity/canonical/verify__replay_later_202.json +++ b/tests/fixtures/parity/canonical/verify__replay_later_202.json @@ -1,13 +1,13 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "99a0a9ca89e1e72c" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued", - "chain_id": "78ac4e9f234ea3bd" } } diff --git a/tests/fixtures/parity/canonical/verify__select_202.json b/tests/fixtures/parity/canonical/verify__select_202.json index be544f2..654ab00 100644 --- a/tests/fixtures/parity/canonical/verify__select_202.json +++ b/tests/fixtures/parity/canonical/verify__select_202.json @@ -1,21 +1,21 @@ { "status": 202, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "batch_id": "7ea9cdbd4064e3cf", "items": [ { - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "claim": "The Earth is round." }, { - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", "claim": "Water boils at 100C at sea level." } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__select_empty_422.json b/tests/fixtures/parity/canonical/verify__select_empty_422.json index 8651afb..bab491b 100644 --- a/tests/fixtures/parity/canonical/verify__select_empty_422.json +++ b/tests/fixtures/parity/canonical/verify__select_empty_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "claims is required.", "code": "blank_input", @@ -18,5 +13,10 @@ "type": "blank_input" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__select_invalid_selection_422.json b/tests/fixtures/parity/canonical/verify__select_invalid_selection_422.json index d8f6dd6..7099c4a 100644 --- a/tests/fixtures/parity/canonical/verify__select_invalid_selection_422.json +++ b/tests/fixtures/parity/canonical/verify__select_invalid_selection_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Selected text was not one of the offered claims: 'The Moon is made of cheese.'", "code": "invalid_selection", @@ -18,5 +13,10 @@ "type": "invalid_selection" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__select_no_selection_pending_409.json b/tests/fixtures/parity/canonical/verify__select_no_selection_pending_409.json index 149402e..47d776a 100644 --- a/tests/fixtures/parity/canonical/verify__select_no_selection_pending_409.json +++ b/tests/fixtures/parity/canonical/verify__select_no_selection_pending_409.json @@ -1,12 +1,12 @@ { "status": 409, + "body": { + "detail": "This task has no pending claim selection.", + "code": "no_selection_pending" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "This task has no pending claim selection.", - "code": "no_selection_pending" } } diff --git a/tests/fixtures/parity/canonical/verify__select_too_many_422.json b/tests/fixtures/parity/canonical/verify__select_too_many_422.json index db644a3..cf16deb 100644 --- a/tests/fixtures/parity/canonical/verify__select_too_many_422.json +++ b/tests/fixtures/parity/canonical/verify__select_too_many_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Cannot select more than 20 claims.", "code": "too_many_items", @@ -18,5 +13,10 @@ "type": "too_many_items" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__select_unknown_task_404.json b/tests/fixtures/parity/canonical/verify__select_unknown_task_404.json index ed0bc13..8c0eaee 100644 --- a/tests/fixtures/parity/canonical/verify__select_unknown_task_404.json +++ b/tests/fixtures/parity/canonical/verify__select_unknown_task_404.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Task not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Task not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/verify__status_cancelled_after_a_while.json b/tests/fixtures/parity/canonical/verify__status_cancelled_after_a_while.json index 799ffa9..40ec53e 100644 --- a/tests/fixtures/parity/canonical/verify__status_cancelled_after_a_while.json +++ b/tests/fixtures/parity/canonical/verify__status_cancelled_after_a_while.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -16,5 +11,10 @@ "retryable": false, "docs_url": "https://lenz.io/docs/errors#cancelled" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_completed.json b/tests/fixtures/parity/canonical/verify__status_completed.json index c0ae291..4cdad25 100644 --- a/tests/fixtures/parity/canonical/verify__status_completed.json +++ b/tests/fixtures/parity/canonical/verify__status_completed.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -30,8 +25,8 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:21:00.123456+00:00", - "completed_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "NASA", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_completed_after_a_while.json b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while.json index c0ae291..4cdad25 100644 --- a/tests/fixtures/parity/canonical/verify__status_completed_after_a_while.json +++ b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -30,8 +25,8 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:21:00.123456+00:00", - "completed_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "NASA", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json index 64eb71f..df91232 100644 --- a/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json index 2cad36e..7d239be 100644 --- a/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/canonical/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/verify__status_completed_modified_at_crosses_midnight_by_minutes.json index 64eb71f..df91232 100644 --- a/tests/fixtures/parity/canonical/verify__status_completed_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/canonical/verify__status_completed_modified_at_crosses_midnight_by_minutes.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/verify__status_completed_modified_at_same_day_hours_apart.json index 2cad36e..7d239be 100644 --- a/tests/fixtures/parity/canonical/verify__status_completed_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/canonical/verify__status_completed_modified_at_same_day_hours_apart.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_failed.json b/tests/fixtures/parity/canonical/verify__status_failed.json index f0674e2..cc029a3 100644 --- a/tests/fixtures/parity/canonical/verify__status_failed.json +++ b/tests/fixtures/parity/canonical/verify__status_failed.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -16,5 +11,10 @@ "retryable": false, "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_failed_after_a_while.json b/tests/fixtures/parity/canonical/verify__status_failed_after_a_while.json index 7deb947..c3694b4 100644 --- a/tests/fixtures/parity/canonical/verify__status_failed_after_a_while.json +++ b/tests/fixtures/parity/canonical/verify__status_failed_after_a_while.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -16,5 +11,10 @@ "retryable": false, "docs_url": "https://lenz.io/docs/errors#internal" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_failed_after_a_while_framing.json b/tests/fixtures/parity/canonical/verify__status_failed_after_a_while_framing.json index 1329048..1774968 100644 --- a/tests/fixtures/parity/canonical/verify__status_failed_after_a_while_framing.json +++ b/tests/fixtures/parity/canonical/verify__status_failed_after_a_while_framing.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -16,5 +11,10 @@ "retryable": true, "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_failed_retryable.json b/tests/fixtures/parity/canonical/verify__status_failed_retryable.json index b7594ed..4fafcc9 100644 --- a/tests/fixtures/parity/canonical/verify__status_failed_retryable.json +++ b/tests/fixtures/parity/canonical/verify__status_failed_retryable.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -16,5 +11,10 @@ "retryable": true, "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_needs_input.json b/tests/fixtures/parity/canonical/verify__status_needs_input.json index 194a4c6..59a23c4 100644 --- a/tests/fixtures/parity/canonical/verify__status_needs_input.json +++ b/tests/fixtures/parity/canonical/verify__status_needs_input.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "needs_input", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -20,5 +15,10 @@ } ], "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_not_a_claim.json b/tests/fixtures/parity/canonical/verify__status_not_a_claim.json index dea790c..335bb1b 100644 --- a/tests/fixtures/parity/canonical/verify__status_not_a_claim.json +++ b/tests/fixtures/parity/canonical/verify__status_not_a_claim.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -16,5 +11,10 @@ "retryable": false, "docs_url": "https://lenz.io/docs/errors#invalid-input" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_not_a_claim_after_a_while.json b/tests/fixtures/parity/canonical/verify__status_not_a_claim_after_a_while.json index d8a3007..771ab68 100644 --- a/tests/fixtures/parity/canonical/verify__status_not_a_claim_after_a_while.json +++ b/tests/fixtures/parity/canonical/verify__status_not_a_claim_after_a_while.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -16,5 +11,10 @@ "retryable": false, "docs_url": "https://lenz.io/docs/errors#invalid-input" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_not_yours_404.json b/tests/fixtures/parity/canonical/verify__status_not_yours_404.json index ed0bc13..8c0eaee 100644 --- a/tests/fixtures/parity/canonical/verify__status_not_yours_404.json +++ b/tests/fixtures/parity/canonical/verify__status_not_yours_404.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Task not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Task not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/verify__status_older_run_completed.json b/tests/fixtures/parity/canonical/verify__status_older_run_completed.json index c0ae291..4cdad25 100644 --- a/tests/fixtures/parity/canonical/verify__status_older_run_completed.json +++ b/tests/fixtures/parity/canonical/verify__status_older_run_completed.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -30,8 +25,8 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:21:00.123456+00:00", - "completed_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "NASA", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_older_run_failed_crashed.json b/tests/fixtures/parity/canonical/verify__status_older_run_failed_crashed.json index 3966046..2899dcb 100644 --- a/tests/fixtures/parity/canonical/verify__status_older_run_failed_crashed.json +++ b/tests/fixtures/parity/canonical/verify__status_older_run_failed_crashed.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -16,5 +11,10 @@ "retryable": false, "docs_url": "https://lenz.io/docs/errors#internal" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_older_run_failed_insufficient_evidence.json b/tests/fixtures/parity/canonical/verify__status_older_run_failed_insufficient_evidence.json index f0674e2..cc029a3 100644 --- a/tests/fixtures/parity/canonical/verify__status_older_run_failed_insufficient_evidence.json +++ b/tests/fixtures/parity/canonical/verify__status_older_run_failed_insufficient_evidence.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -16,5 +11,10 @@ "retryable": false, "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_older_run_in_progress.json b/tests/fixtures/parity/canonical/verify__status_older_run_in_progress.json index 8ff9472..5e5d47b 100644 --- a/tests/fixtures/parity/canonical/verify__status_older_run_in_progress.json +++ b/tests/fixtures/parity/canonical/verify__status_older_run_in_progress.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -12,8 +7,13 @@ "step": "research", "index": 2, "total": 5, - "elapsed_seconds": 2, + "elapsed_seconds": 1, "poll_after_seconds": 5 } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_processing.json b/tests/fixtures/parity/canonical/verify__status_processing.json index 8ff9472..5e5d47b 100644 --- a/tests/fixtures/parity/canonical/verify__status_processing.json +++ b/tests/fixtures/parity/canonical/verify__status_processing.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -12,8 +7,13 @@ "step": "research", "index": 2, "total": 5, - "elapsed_seconds": 2, + "elapsed_seconds": 1, "poll_after_seconds": 5 } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_processing_after_a_while.json b/tests/fixtures/parity/canonical/verify__status_processing_after_a_while.json index 077dee8..e0638f1 100644 --- a/tests/fixtures/parity/canonical/verify__status_processing_after_a_while.json +++ b/tests/fixtures/parity/canonical/verify__status_processing_after_a_while.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -12,8 +7,13 @@ "step": "adjudication", "index": 4, "total": 5, - "elapsed_seconds": 2, + "elapsed_seconds": 1, "poll_after_seconds": 5 } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_task_stuck.json b/tests/fixtures/parity/canonical/verify__status_task_stuck.json index 8230e8c..4ca4162 100644 --- a/tests/fixtures/parity/canonical/verify__status_task_stuck.json +++ b/tests/fixtures/parity/canonical/verify__status_task_stuck.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -16,5 +11,10 @@ "retryable": true, "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__status_unknown_404.json b/tests/fixtures/parity/canonical/verify__status_unknown_404.json index ed0bc13..8c0eaee 100644 --- a/tests/fixtures/parity/canonical/verify__status_unknown_404.json +++ b/tests/fixtures/parity/canonical/verify__status_unknown_404.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Task not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Task not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/verify__submit_202.json b/tests/fixtures/parity/canonical/verify__submit_202.json index b510371..d47aeaf 100644 --- a/tests/fixtures/parity/canonical/verify__submit_202.json +++ b/tests/fixtures/parity/canonical/verify__submit_202.json @@ -1,12 +1,12 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/verify__submit_202_options.json b/tests/fixtures/parity/canonical/verify__submit_202_options.json index b510371..d47aeaf 100644 --- a/tests/fixtures/parity/canonical/verify__submit_202_options.json +++ b/tests/fixtures/parity/canonical/verify__submit_202_options.json @@ -1,12 +1,12 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/verify__submit_202_text_alias.json b/tests/fixtures/parity/canonical/verify__submit_202_text_alias.json index b510371..d47aeaf 100644 --- a/tests/fixtures/parity/canonical/verify__submit_202_text_alias.json +++ b/tests/fixtures/parity/canonical/verify__submit_202_text_alias.json @@ -1,12 +1,12 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued" } } diff --git a/tests/fixtures/parity/canonical/verify__unauthenticated_401.json b/tests/fixtures/parity/canonical/verify__unauthenticated_401.json index 1c3df51..dcdaad0 100644 --- a/tests/fixtures/parity/canonical/verify__unauthenticated_401.json +++ b/tests/fixtures/parity/canonical/verify__unauthenticated_401.json @@ -1,12 +1,12 @@ { "status": 401, + "body": { + "detail": "Unauthorized", + "code": "not_authenticated" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized", - "code": "not_authenticated" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_200.json b/tests/fixtures/parity/canonical/verify__verification_200.json index e6d5f88..54fbdb7 100644 --- a/tests/fixtures/parity/canonical/verify__verification_200.json +++ b/tests/fixtures/parity/canonical/verify__verification_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,8 +22,8 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "NASA", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_200_covered.json b/tests/fixtures/parity/canonical/verify__verification_200_covered.json index ab1972e..c9c3df6 100644 --- a/tests/fixtures/parity/canonical/verify__verification_200_covered.json +++ b/tests/fixtures/parity/canonical/verify__verification_200_covered.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,8 +22,8 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "NASA", @@ -81,13 +76,18 @@ "coverage": { "status": "covered", "reasons": [], - "certificate_id": "df2c8d27663c61f5a32c2c628d182f81", - "certificate_url": "https://lenz.io/certificate/df2c8d27663c61f5a32c2c628d182f81", + "certificate_id": "95b0f3dd008b46846b6dd6b15099e2b3", + "certificate_url": "https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3", "as_of": "2026-03-10T12:01:30+00:00", "currency": "EUR", "cap": 10000, "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_crosses_midnight_by_minutes.json index 9b01ef7..5c62918 100644 --- a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_crosses_midnight_by_minutes.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_null.json b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_null.json index 3cd999b..54fbdb7 100644 --- a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_null.json +++ b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_null.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,8 +22,8 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "NASA", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_same_day_hours_apart.json index 6a57a82..cb9d0dd 100644 --- a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_same_day_hours_apart.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_set.json b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_set.json index 9b01ef7..5c62918 100644 --- a/tests/fixtures/parity/canonical/verify__verification_200_modified_at_set.json +++ b/tests/fixtures/parity/canonical/verify__verification_200_modified_at_set.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_200_result_json_conclusion_only.json b/tests/fixtures/parity/canonical/verify__verification_200_result_json_conclusion_only.json index 68f5a3f..eb7471c 100644 --- a/tests/fixtures/parity/canonical/verify__verification_200_result_json_conclusion_only.json +++ b/tests/fixtures/parity/canonical/verify__verification_200_result_json_conclusion_only.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -20,8 +15,8 @@ "executive_summary": "The claim is verified.", "warnings": [], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [], "audit": { "adjudication_summary": "", @@ -52,5 +47,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_200_result_json_empty.json b/tests/fixtures/parity/canonical/verify__verification_200_result_json_empty.json index 68f5a3f..eb7471c 100644 --- a/tests/fixtures/parity/canonical/verify__verification_200_result_json_empty.json +++ b/tests/fixtures/parity/canonical/verify__verification_200_result_json_empty.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -20,8 +15,8 @@ "executive_summary": "The claim is verified.", "warnings": [], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [], "audit": { "adjudication_summary": "", @@ -52,5 +47,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_200_result_json_old_shape_strings.json b/tests/fixtures/parity/canonical/verify__verification_200_result_json_old_shape_strings.json index d236164..b2a825a 100644 --- a/tests/fixtures/parity/canonical/verify__verification_200_result_json_old_shape_strings.json +++ b/tests/fixtures/parity/canonical/verify__verification_200_result_json_old_shape_strings.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -20,8 +15,8 @@ "executive_summary": "The claim is verified.", "warnings": [], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "", @@ -68,5 +63,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_404.json b/tests/fixtures/parity/canonical/verify__verification_404.json index f1a8c33..775d847 100644 --- a/tests/fixtures/parity/canonical/verify__verification_404.json +++ b/tests/fixtures/parity/canonical/verify__verification_404.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_by_task_id_200.json b/tests/fixtures/parity/canonical/verify__verification_by_task_id_200.json index e6d5f88..54fbdb7 100644 --- a/tests/fixtures/parity/canonical/verify__verification_by_task_id_200.json +++ b/tests/fixtures/parity/canonical/verify__verification_by_task_id_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,8 +22,8 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "NASA", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_failed_409.json b/tests/fixtures/parity/canonical/verify__verification_failed_409.json index b7c3f82..1a8058b 100644 --- a/tests/fixtures/parity/canonical/verify__verification_failed_409.json +++ b/tests/fixtures/parity/canonical/verify__verification_failed_409.json @@ -1,10 +1,5 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This check failed and has no result.", "code": "verification_failed", @@ -19,5 +14,10 @@ "retryable": false, "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" } + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_failed_409_not_a_claim_after_a_while.json b/tests/fixtures/parity/canonical/verify__verification_failed_409_not_a_claim_after_a_while.json index 9479d57..62a1cc6 100644 --- a/tests/fixtures/parity/canonical/verify__verification_failed_409_not_a_claim_after_a_while.json +++ b/tests/fixtures/parity/canonical/verify__verification_failed_409_not_a_claim_after_a_while.json @@ -1,10 +1,5 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This check failed and has no result.", "code": "verification_failed", @@ -19,5 +14,10 @@ "retryable": false, "docs_url": "https://lenz.io/docs/errors#invalid-input" } + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_not_ready_409.json b/tests/fixtures/parity/canonical/verify__verification_not_ready_409.json index d5ace3f..dae092f 100644 --- a/tests/fixtures/parity/canonical/verify__verification_not_ready_409.json +++ b/tests/fixtures/parity/canonical/verify__verification_not_ready_409.json @@ -1,15 +1,15 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This check is still running.", "code": "verification_not_ready", "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad", "hint": "Poll GET /verify/status/7cff18da2d979d6370e54a160be121ad until it completes, then read its result." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_not_yours_404.json b/tests/fixtures/parity/canonical/verify__verification_not_yours_404.json index f1a8c33..775d847 100644 --- a/tests/fixtures/parity/canonical/verify__verification_not_yours_404.json +++ b/tests/fixtures/parity/canonical/verify__verification_not_yours_404.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_public_anonymous.json b/tests/fixtures/parity/canonical/verify__verification_public_anonymous.json index aec1fd3..9b93c51 100644 --- a/tests/fixtures/parity/canonical/verify__verification_public_anonymous.json +++ b/tests/fixtures/parity/canonical/verify__verification_public_anonymous.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,8 +22,8 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "NASA", @@ -79,5 +74,10 @@ }, "language": "en", "coverage": null + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_public_of_another_user.json b/tests/fixtures/parity/canonical/verify__verification_public_of_another_user.json index 4ccbda8..4727423 100644 --- a/tests/fixtures/parity/canonical/verify__verification_public_of_another_user.json +++ b/tests/fixtures/parity/canonical/verify__verification_public_of_another_user.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,8 +22,8 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "NASA", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_unknown_task_404.json b/tests/fixtures/parity/canonical/verify__verification_unknown_task_404.json index e577e2e..2833a7f 100644 --- a/tests/fixtures/parity/canonical/verify__verification_unknown_task_404.json +++ b/tests/fixtures/parity/canonical/verify__verification_unknown_task_404.json @@ -1,13 +1,13 @@ { "status": 404, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Not found.", "code": "not_found", "hint": "Unknown id. If this is a task_id, poll GET /verify/status/dddddddddddddddddddddddddddddddd for its status." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_zero_retention_expired_410.json b/tests/fixtures/parity/canonical/verify__verification_zero_retention_expired_410.json index 010b258..924d468 100644 --- a/tests/fixtures/parity/canonical/verify__verification_zero_retention_expired_410.json +++ b/tests/fixtures/parity/canonical/verify__verification_zero_retention_expired_410.json @@ -1,13 +1,13 @@ { "status": 410, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This verification is no longer available: its account removes verifications after a set period.", "code": "purged", "purged_at": "2026-10-01T09:07:00.123456+00:00" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__verification_zero_retention_served.json b/tests/fixtures/parity/canonical/verify__verification_zero_retention_served.json index fca733d..ec77f26 100644 --- a/tests/fixtures/parity/canonical/verify__verification_zero_retention_served.json +++ b/tests/fixtures/parity/canonical/verify__verification_zero_retention_served.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,8 +22,8 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", - "completed_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "NASA", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/canonical/verify__webhook_secret_missing_422.json b/tests/fixtures/parity/canonical/verify__webhook_secret_missing_422.json new file mode 100644 index 0000000..85482fc --- /dev/null +++ b/tests/fixtures/parity/canonical/verify__webhook_secret_missing_422.json @@ -0,0 +1,22 @@ +{ + "status": 422, + "body": { + "detail": "webhook_url was supplied but this API key has no HMAC secret. Generate one at https://lenz.io/api-credentials (Webhooks panel) before submitting webhook-delivered calls.", + "code": "webhook_secret_missing", + "errors": [ + { + "loc": [ + "body", + "webhook_url" + ], + "msg": "webhook_url was supplied but this API key has no HMAC secret. Generate one at https://lenz.io/api-credentials (Webhooks panel) before submitting webhook-delivered calls.", + "type": "webhook_secret_missing" + } + ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/canonical/webhook__certificate_timestamped.json b/tests/fixtures/parity/canonical/webhook__certificate_timestamped.json index f2093db..422b1ce 100644 --- a/tests/fixtures/parity/canonical/webhook__certificate_timestamped.json +++ b/tests/fixtures/parity/canonical/webhook__certificate_timestamped.json @@ -1,17 +1,16 @@ { "status": 200, - "headers": {}, "body": { "event": "certificate.timestamped", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "task_id": "7cff18da2d979d6370e54a160be121ad", "verification_id": "68ca4aaf", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", - "batch_id": null, "status": "completed", "coverage": { "status": "covered", "reasons": [], - "certificate_id": "def7232d27eda03cf261569aee9948c5", - "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "certificate_id": "95b0f3dd008b46846b6dd6b15099e2b3", + "certificate_url": "https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3", "as_of": "2026-09-03T10:00:00+00:00", "currency": "EUR", "cap": 10000, @@ -19,7 +18,7 @@ "terms_version": "v1" }, "attempt": 1, - "delivered_at": "2026-10-01T09:28:00.123456+00:00", - "event_id": "evt_0b92b443eb69b9c71434fdc6" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__certificate_timestamped_review_child.json b/tests/fixtures/parity/canonical/webhook__certificate_timestamped_review_child.json index 80582ef..0a4075b 100644 --- a/tests/fixtures/parity/canonical/webhook__certificate_timestamped_review_child.json +++ b/tests/fixtures/parity/canonical/webhook__certificate_timestamped_review_child.json @@ -1,26 +1,25 @@ { "status": 200, - "headers": {}, "body": { "event": "certificate.timestamped", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "task_id": "7cff18da2d979d6370e54a160be121ad", "verification_id": "68ca4aaf", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", - "batch_id": null, + "review_id": "d6b2bd72", "status": "completed", "coverage": { "status": "covered", "reasons": [], - "certificate_id": "def7232d27eda03cf261569aee9948c5", - "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "certificate_id": "95b0f3dd008b46846b6dd6b15099e2b3", + "certificate_url": "https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3", "as_of": "2026-09-03T10:00:00+00:00", "currency": "EUR", "cap": 10000, "aggregate": 500000, "terms_version": "v1" }, - "review_id": "d6b2bd72", "attempt": 1, - "delivered_at": "2026-10-01T09:28:00.123456+00:00", - "event_id": "evt_0b92b443eb69b9c71434fdc6" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__citecheck_completed.json b/tests/fixtures/parity/canonical/webhook__citecheck_completed.json index ce60399..e5c5a3d 100644 --- a/tests/fixtures/parity/canonical/webhook__citecheck_completed.json +++ b/tests/fixtures/parity/canonical/webhook__citecheck_completed.json @@ -1,17 +1,16 @@ { "status": 200, - "headers": {}, "body": { "event": "citecheck.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "citecheck_id": "98c0e7d5", + "citecheck_id": "8eb49302", "status": "completed", "citecheck": { - "citecheck_id": "98c0e7d5", + "citecheck_id": "8eb49302", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:28:00.123456Z", - "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -21,7 +20,7 @@ "citations_found": 2, "citations_selected": 2, "citation_limit": 2, - "citation_limit_reached": false, + "citation_limit_exceeded": false, "citation_checks": { "checked": 2, "unchecked": 0, @@ -128,6 +127,7 @@ "more_citations": [] }, "attempt": 1, - "delivered_at": "2026-10-01T09:42:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__citecheck_failed.json b/tests/fixtures/parity/canonical/webhook__citecheck_failed.json index 7474d1c..809b573 100644 --- a/tests/fixtures/parity/canonical/webhook__citecheck_failed.json +++ b/tests/fixtures/parity/canonical/webhook__citecheck_failed.json @@ -1,17 +1,16 @@ { "status": 200, - "headers": {}, "body": { "event": "citecheck.failed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "citecheck_id": "98c0e7d5", + "citecheck_id": "8eb49302", "status": "failed", "citecheck": { - "citecheck_id": "98c0e7d5", + "citecheck_id": "8eb49302", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:28:00.123456Z", - "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -21,7 +20,7 @@ "citations_found": null, "citations_selected": null, "citation_limit": 20, - "citation_limit_reached": null, + "citation_limit_exceeded": null, "citation_checks": null, "citation_issues": 0 }, @@ -32,15 +31,17 @@ "citation_issues": [], "citation_failures": [], "failure": { - "failure_reason": "no_citations", + "code": "no_citations", + "detail": "The text holds no citation to check.", + "hint": "The text has no citation to check: no link, DOI or numbered reference with one.", "failure_class": "invalid_input", "retryable": false, - "hint": "The text has no citation to check: no link, DOI or numbered reference with one.", "docs_url": "https://lenz.io/docs/errors#invalid-input" }, "more_citations": null }, "attempt": 1, - "delivered_at": "2026-10-01T09:42:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__review_completed.json b/tests/fixtures/parity/canonical/webhook__review_completed.json index 78cf7d2..35b6ad5 100644 --- a/tests/fixtures/parity/canonical/webhook__review_completed.json +++ b/tests/fixtures/parity/canonical/webhook__review_completed.json @@ -1,18 +1,17 @@ { "status": 200, - "headers": {}, "body": { "event": "review.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "completed", "review": { - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:28:00.123456Z", - "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -30,9 +29,10 @@ "suggest_edits": false }, "summary": { + "claims_found": 1, "claims_selected": 1, "claim_limit": 20, - "claim_limit_reached": false, + "claim_limit_exceeded": false, "input_truncated": false, "assessments": { "completed": 1, @@ -47,7 +47,7 @@ "citations_found": null, "citations_selected": null, "citation_limit": null, - "citation_limit_reached": null, + "citation_limit_exceeded": null, "citation_checks": null, "citation_issues": 0, "citations_skipped": null @@ -64,10 +64,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "8ceed6f0", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", - "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -99,13 +99,11 @@ "status": "completed", "verdict": "False", "confidence": "high", + "verification_url": null, "rationale": null, "dissent": null, - "verification_url": null, - "error_code": null, - "identified_claims": [], - "hint": null, "suggested_rewrite": null, + "more_claims": [], "failure": null }, "escalation": { @@ -117,8 +115,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "5ccac77f53ff49328ec134fb29d66542", - "verification_id": "8ceed6f0", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", "language": "en", "visibility": "private", @@ -134,10 +132,10 @@ "warnings": [ "w1" ], - "created_at": "2026-10-01T09:56:00.123456+00:00", - "modified_at": null, - "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", - "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "completed_at": "2026-10-01T09:14:00.123456+00:00", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": null @@ -150,6 +148,7 @@ "more_citations": [] }, "attempt": 1, - "delivered_at": "2026-10-01T10:03:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__review_completed_key_default_url.json b/tests/fixtures/parity/canonical/webhook__review_completed_key_default_url.json index 0631d53..b1bd673 100644 --- a/tests/fixtures/parity/canonical/webhook__review_completed_key_default_url.json +++ b/tests/fixtures/parity/canonical/webhook__review_completed_key_default_url.json @@ -1,18 +1,17 @@ { "status": 200, - "headers": {}, "body": { "event": "review.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "completed", "review": { - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:28:00.123456Z", - "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -30,9 +29,10 @@ "suggest_edits": false }, "summary": { + "claims_found": 1, "claims_selected": 1, "claim_limit": 20, - "claim_limit_reached": false, + "claim_limit_exceeded": false, "input_truncated": false, "assessments": { "completed": 1, @@ -47,7 +47,7 @@ "citations_found": null, "citations_selected": null, "citation_limit": null, - "citation_limit_reached": null, + "citation_limit_exceeded": null, "citation_checks": null, "citation_issues": 0, "citations_skipped": null @@ -75,13 +75,11 @@ "status": "completed", "verdict": "True", "confidence": "high", + "verification_url": null, "rationale": null, "dissent": null, - "verification_url": null, - "error_code": null, - "identified_claims": [], - "hint": null, "suggested_rewrite": null, + "more_claims": [], "failure": null }, "escalation": { @@ -99,6 +97,7 @@ "more_citations": [] }, "attempt": 1, - "delivered_at": "2026-10-01T09:42:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__review_completed_oversized_rebuilt.json b/tests/fixtures/parity/canonical/webhook__review_completed_oversized_rebuilt.json index e96d947..3f18193 100644 --- a/tests/fixtures/parity/canonical/webhook__review_completed_oversized_rebuilt.json +++ b/tests/fixtures/parity/canonical/webhook__review_completed_oversized_rebuilt.json @@ -1,10 +1,10 @@ { "status": 200, - "headers": {}, "body": { "event": "review.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "completed" - } + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__review_failed.json b/tests/fixtures/parity/canonical/webhook__review_failed.json index f382954..40f0ca5 100644 --- a/tests/fixtures/parity/canonical/webhook__review_failed.json +++ b/tests/fixtures/parity/canonical/webhook__review_failed.json @@ -1,18 +1,17 @@ { "status": 200, - "headers": {}, "body": { "event": "review.failed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "failed", "review": { - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:28:00.123456Z", - "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -30,9 +29,10 @@ "suggest_edits": false }, "summary": { + "claims_found": null, "claims_selected": null, "claim_limit": 20, - "claim_limit_reached": null, + "claim_limit_exceeded": null, "input_truncated": false, "assessments": null, "verifications": null, @@ -40,7 +40,7 @@ "citations_found": null, "citations_selected": null, "citation_limit": null, - "citation_limit_reached": null, + "citation_limit_exceeded": null, "citation_checks": null, "citation_issues": 0, "citations_skipped": null @@ -56,10 +56,11 @@ "claims": [], "citations": [], "failure": { - "failure_reason": "no_claim", + "code": "no_checkable_claim", + "detail": "No claim in the input could be checked against public evidence.", + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", "failure_class": "invalid_input", "retryable": false, - "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", "docs_url": "https://lenz.io/docs/errors#invalid-input" }, "more_claims": null, @@ -67,6 +68,7 @@ "more_citations": null }, "attempt": 1, - "delivered_at": "2026-10-01T09:42:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__test_fire.json b/tests/fixtures/parity/canonical/webhook__test_fire.json new file mode 100644 index 0000000..1d3d49b --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__test_fire.json @@ -0,0 +1,12 @@ +{ + "status": 200, + "body": { + "attempt": 1, + "delivered_at": "2026-10-01T11:07:00.123456+00:00", + "event": "webhook.test", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "status": "test", + "task_id": "test_7cff18da2d979d63" + }, + "headers": {} +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_completed.json b/tests/fixtures/parity/canonical/webhook__verification_completed.json index 64c7f2c..71884cd 100644 --- a/tests/fixtures/parity/canonical/webhook__verification_completed.json +++ b/tests/fixtures/parity/canonical/webhook__verification_completed.json @@ -1,16 +1,14 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.completed", - "event_id": "evt_0b92b443eb69b9c71434fdc6", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "task_id": "7cff18da2d979d6370e54a160be121ad", "verification_id": "68ca4aaf", - "batch_id": null, "status": "completed", "verification": { "status": "completed", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", @@ -37,7 +35,8 @@ "Only two sources were found." ], "suggested_rewrite": "The Eiffel Tower is in Paris.", - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "Example Encyclopedia", @@ -99,11 +98,11 @@ "cap": 10000, "aggregate": 500000, "terms_version": "v1" - }, - "completed_at": "2026-10-01T09:21:00.123456+00:00" + } } }, "attempt": 1, - "delivered_at": "2026-10-01T09:28:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__verification_completed_in_batch.json b/tests/fixtures/parity/canonical/webhook__verification_completed_in_batch.json index f5a306c..507e63b 100644 --- a/tests/fixtures/parity/canonical/webhook__verification_completed_in_batch.json +++ b/tests/fixtures/parity/canonical/webhook__verification_completed_in_batch.json @@ -1,16 +1,15 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.completed", - "event_id": "evt_0b92b443eb69b9c71434fdc6", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "task_id": "7cff18da2d979d6370e54a160be121ad", "verification_id": "68ca4aaf", - "batch_id": "4ee0c3aa1b671eaa", + "batch_id": "7ea9cdbd4064e3cf", "status": "completed", "verification": { "status": "completed", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", @@ -37,7 +36,8 @@ "Only two sources were found." ], "suggested_rewrite": "The Eiffel Tower is in Paris.", - "created_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "completed_at": "2026-10-01T09:07:00.123456+00:00", "sources": [ { "source_name": "Example Encyclopedia", @@ -99,11 +99,11 @@ "cap": 10000, "aggregate": 500000, "terms_version": "v1" - }, - "completed_at": "2026-10-01T09:28:00.123456+00:00" + } } }, "attempt": 1, - "delivered_at": "2026-10-01T09:35:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json index 2bbe988..dc19418 100644 --- a/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json @@ -1,16 +1,14 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.completed", - "event_id": "evt_0b92b443eb69b9c71434fdc6", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "task_id": "7cff18da2d979d6370e54a160be121ad", "verification_id": "68ca4aaf", - "batch_id": null, "status": "completed", "verification": { "status": "completed", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", @@ -38,6 +36,7 @@ ], "suggested_rewrite": "The Eiffel Tower is in Paris.", "created_at": "2026-10-01T23:55:00.123456+00:00", + "completed_at": "2026-10-02T00:03:00.123456+00:00", "sources": [ { "source_name": "Example Encyclopedia", @@ -99,11 +98,11 @@ "cap": 10000, "aggregate": 500000, "terms_version": "v1" - }, - "completed_at": "2026-10-02T00:03:00.123456+00:00" + } } }, "attempt": 1, - "delivered_at": "2026-10-01T09:35:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_same_day_hours_apart.json index fa61911..189ca65 100644 --- a/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/canonical/webhook__verification_completed_modified_at_same_day_hours_apart.json @@ -1,16 +1,14 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.completed", - "event_id": "evt_0b92b443eb69b9c71434fdc6", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "task_id": "7cff18da2d979d6370e54a160be121ad", "verification_id": "68ca4aaf", - "batch_id": null, "status": "completed", "verification": { "status": "completed", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", @@ -38,6 +36,7 @@ ], "suggested_rewrite": "The Eiffel Tower is in Paris.", "created_at": "2026-10-01T08:00:00.123456+00:00", + "completed_at": "2026-10-01T20:00:00.123456+00:00", "sources": [ { "source_name": "Example Encyclopedia", @@ -99,11 +98,11 @@ "cap": 10000, "aggregate": 500000, "terms_version": "v1" - }, - "completed_at": "2026-10-01T20:00:00.123456+00:00" + } } }, "attempt": 1, - "delivered_at": "2026-10-01T09:28:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__verification_completed_sparse_result.json b/tests/fixtures/parity/canonical/webhook__verification_completed_sparse_result.json new file mode 100644 index 0000000..91f7632 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_completed_sparse_result.json @@ -0,0 +1,22 @@ +{ + "status": 200, + "body": { + "event": "verification.completed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", + "status": "completed", + "verification": { + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "result": { + "verification_id": "68ca4aaf", + "claim": "The Eiffel Tower is in Berlin.", + "language": "en" + } + }, + "attempt": 1, + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_failed_error_none.json b/tests/fixtures/parity/canonical/webhook__verification_failed_error_none.json new file mode 100644 index 0000000..e858af3 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_failed_error_none.json @@ -0,0 +1,24 @@ +{ + "status": 200, + "body": { + "event": "verification.failed", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "failed", + "verification": { + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "failure": { + "code": "", + "detail": "The check stopped before it finished.", + "hint": null, + "failure_class": "internal", + "retryable": false, + "docs_url": "https://lenz.io/docs/errors#internal" + } + }, + "attempt": 1, + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_failed_insufficient_evidence.json b/tests/fixtures/parity/canonical/webhook__verification_failed_insufficient_evidence.json index f47e7ee..7d3a875 100644 --- a/tests/fixtures/parity/canonical/webhook__verification_failed_insufficient_evidence.json +++ b/tests/fixtures/parity/canonical/webhook__verification_failed_insufficient_evidence.json @@ -1,26 +1,24 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.failed", - "event_id": "evt_7cff18da2d979d6370e54a16", + "event_id": "evt_09301870aba4e8f6ae33ff60", "task_id": "7cff18da2d979d6370e54a160be121ad", - "verification_id": null, - "batch_id": null, "status": "failed", "verification": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", "failure": { "code": "research_insufficient", - "detail": "A sentence on what happened.", + "detail": "Too few sources about the claim were found to judge it.", "hint": null, "failure_class": "insufficient_evidence", "retryable": false, - "docs_url": "https://lenz.io/docs/errors" + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" } }, "attempt": 1, - "delivered_at": "2026-10-01T09:14:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__verification_failed_not_a_claim.json b/tests/fixtures/parity/canonical/webhook__verification_failed_not_a_claim.json index cf284d5..e25ed20 100644 --- a/tests/fixtures/parity/canonical/webhook__verification_failed_not_a_claim.json +++ b/tests/fixtures/parity/canonical/webhook__verification_failed_not_a_claim.json @@ -1,26 +1,24 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.failed", - "event_id": "evt_7cff18da2d979d6370e54a16", + "event_id": "evt_09301870aba4e8f6ae33ff60", "task_id": "7cff18da2d979d6370e54a160be121ad", - "verification_id": null, - "batch_id": null, "status": "failed", "verification": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", "failure": { "code": "no_checkable_claim", - "detail": "A sentence on what happened.", - "hint": null, + "detail": "No claim in the input could be checked against public evidence.", + "hint": "It is a request to write an essay. Send one factual claim, or run the text through /extract to enumerate its claims.", "failure_class": "invalid_input", "retryable": false, - "docs_url": "https://lenz.io/docs/errors" + "docs_url": "https://lenz.io/docs/errors#invalid-input" } }, "attempt": 1, - "delivered_at": "2026-10-01T09:14:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__verification_failed_upstream_unavailable.json b/tests/fixtures/parity/canonical/webhook__verification_failed_upstream_unavailable.json index 322b4ba..926b1c1 100644 --- a/tests/fixtures/parity/canonical/webhook__verification_failed_upstream_unavailable.json +++ b/tests/fixtures/parity/canonical/webhook__verification_failed_upstream_unavailable.json @@ -1,26 +1,24 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.failed", - "event_id": "evt_7cff18da2d979d6370e54a16", + "event_id": "evt_09301870aba4e8f6ae33ff60", "task_id": "7cff18da2d979d6370e54a160be121ad", - "verification_id": null, - "batch_id": null, "status": "failed", "verification": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", "failure": { "code": "framing_failed", - "detail": "A sentence on what happened.", + "detail": "The input could not be read as a claim.", "hint": null, "failure_class": "upstream_unavailable", "retryable": true, - "docs_url": "https://lenz.io/docs/errors" + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" } }, "attempt": 1, - "delivered_at": "2026-10-01T09:14:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/canonical/webhook__verification_needs_input_hint_none.json b/tests/fixtures/parity/canonical/webhook__verification_needs_input_hint_none.json new file mode 100644 index 0000000..3377675 --- /dev/null +++ b/tests/fixtures/parity/canonical/webhook__verification_needs_input_hint_none.json @@ -0,0 +1,24 @@ +{ + "status": 200, + "body": { + "event": "verification.needs_input", + "event_id": "evt_09301870aba4e8f6ae33ff60", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "needs_input", + "verification": { + "status": "needs_input", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "reason": "multi_claim", + "claims": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "domain": "" + } + ], + "hint": null + }, + "attempt": 1, + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} +} diff --git a/tests/fixtures/parity/canonical/webhook__verification_needs_input_multi_claim.json b/tests/fixtures/parity/canonical/webhook__verification_needs_input_multi_claim.json index 0961dbb..3e04f93 100644 --- a/tests/fixtures/parity/canonical/webhook__verification_needs_input_multi_claim.json +++ b/tests/fixtures/parity/canonical/webhook__verification_needs_input_multi_claim.json @@ -1,18 +1,14 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.needs_input", - "event_id": "evt_7cff18da2d979d6370e54a16", + "event_id": "evt_09301870aba4e8f6ae33ff60", "task_id": "7cff18da2d979d6370e54a160be121ad", - "verification_id": null, - "batch_id": null, "status": "needs_input", "verification": { "status": "needs_input", "task_id": "7cff18da2d979d6370e54a160be121ad", "reason": "multi_claim", - "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.", "claims": [ { "claim": "The Earth is round.", @@ -22,9 +18,11 @@ "claim": "The Moon is made of cheese.", "domain": "Science" } - ] + ], + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select." }, "attempt": 1, - "delivered_at": "2026-10-01T09:14:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/expected/account__api_root.json b/tests/fixtures/parity/expected/account__api_root.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__api_root.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__ask_history_after_reset.json b/tests/fixtures/parity/expected/account__ask_history_after_reset.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__ask_history_after_reset.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__ask_history_after_send.json b/tests/fixtures/parity/expected/account__ask_history_after_send.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__ask_history_after_send.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__ask_history_empty.json b/tests/fixtures/parity/expected/account__ask_history_empty.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__ask_history_empty.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__ask_history_messages.json b/tests/fixtures/parity/expected/account__ask_history_messages.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__ask_history_messages.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__ask_reset.json b/tests/fixtures/parity/expected/account__ask_reset.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__ask_reset.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__ask_send.json b/tests/fixtures/parity/expected/account__ask_send.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__ask_send.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__ask_send_language.json b/tests/fixtures/parity/expected/account__ask_send_language.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__ask_send_language.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__library_empty.json b/tests/fixtures/parity/expected/account__library_empty.json index d628806..2184439 100644 --- a/tests/fixtures/parity/expected/account__library_empty.json +++ b/tests/fixtures/parity/expected/account__library_empty.json @@ -5,5 +5,12 @@ "page_size": 20, "total": 0 }, - "render_json": null + "dump_unset": { + "items": [], + "page": 1, + "page_size": 20, + "total": 0 + }, + "render_json": null, + "repr": "LibraryList(items=[], total=0, page=1, page_size=20)" } diff --git a/tests/fixtures/parity/expected/account__library_item_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/account__library_item_modified_at_crosses_midnight_by_minutes.json index dedd58d..d6bafee 100644 --- a/tests/fixtures/parity/expected/account__library_item_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/expected/account__library_item_modified_at_crosses_midnight_by_minutes.json @@ -21,5 +21,28 @@ "page_size": 20, "total": 1 }, - "render_json": null + "dump_unset": { + "items": [ + { + "claim": "A library claim.", + "confidence": "low", + "created_at": "2026-10-01T23:55:00.123456+00:00", + "domain": "", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + } + ], + "page": 1, + "page_size": 20, + "total": 1 + }, + "render_json": null, + "repr": "LibraryList(items=[LibraryItem(verification_id='68ca4aaf', claim='A library claim.', domain='', entities=[], verdict='True', confidence='low', lenz_score=10, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T23:55:00.123456+00:00', modified_at='2026-10-02T00:03:00.123456+00:00', language='en')], total=1, page=1, page_size=20)" } diff --git a/tests/fixtures/parity/expected/account__library_item_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/account__library_item_modified_at_same_day_hours_apart.json index 7edcd92..3e2043e 100644 --- a/tests/fixtures/parity/expected/account__library_item_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/expected/account__library_item_modified_at_same_day_hours_apart.json @@ -21,5 +21,28 @@ "page_size": 20, "total": 1 }, - "render_json": null + "dump_unset": { + "items": [ + { + "claim": "A library claim.", + "confidence": "low", + "created_at": "2026-10-01T08:00:00.123456+00:00", + "domain": "", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + } + ], + "page": 1, + "page_size": 20, + "total": 1 + }, + "render_json": null, + "repr": "LibraryList(items=[LibraryItem(verification_id='68ca4aaf', claim='A library claim.', domain='', entities=[], verdict='True', confidence='low', lenz_score=10, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T08:00:00.123456+00:00', modified_at=None, language='en')], total=1, page=1, page_size=20)" } diff --git a/tests/fixtures/parity/expected/account__library_items.json b/tests/fixtures/parity/expected/account__library_items.json index 72a7d37..00d7d2f 100644 --- a/tests/fixtures/parity/expected/account__library_items.json +++ b/tests/fixtures/parity/expected/account__library_items.json @@ -4,7 +4,7 @@ { "claim": "Library claim 0.", "confidence": "low", - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "domain": "Science", "entities": [], "executive_summary": "The claim is verified.", @@ -19,7 +19,22 @@ { "claim": "Library claim 1.", "confidence": "low", - "created_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf" + }, + { + "claim": "Library claim 2.", + "confidence": "low", + "created_at": "2026-10-01T09:21:00.123456+00:00", "domain": "Science", "entities": [], "executive_summary": "The claim is verified.", @@ -30,11 +45,48 @@ "suggested_rewrite": null, "verdict": "True", "verification_id": "7c83247c" + } + ], + "page": 1, + "page_size": 20, + "total": 3 + }, + "dump_unset": { + "items": [ + { + "claim": "Library claim 0.", + "confidence": "low", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + }, + { + "claim": "Library claim 1.", + "confidence": "low", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "4d44dfaf" }, { "claim": "Library claim 2.", "confidence": "low", - "created_at": "2026-10-01T09:42:00.123456+00:00", + "created_at": "2026-10-01T09:21:00.123456+00:00", "domain": "Science", "entities": [], "executive_summary": "The claim is verified.", @@ -44,12 +96,13 @@ "modified_at": null, "suggested_rewrite": null, "verdict": "True", - "verification_id": "b79019e4" + "verification_id": "7c83247c" } ], "page": 1, "page_size": 20, "total": 3 }, - "render_json": null + "render_json": null, + "repr": "LibraryList(items=[LibraryItem(verification_id='68ca4aaf', claim='Library claim 0.', domain='Science', entities=[], verdict='True', confidence='low', lenz_score=10, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en'), LibraryItem(verification_id='4d44dfaf', claim='Library claim 1.', domain='Science', entities=[], verdict='True', confidence='low', lenz_score=10, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T09:14:00.123456+00:00', modified_at=None, language='en'), LibraryItem(verification_id='7c83247c', claim='Library claim 2.', domain='Science', entities=[], verdict='True', confidence='low', lenz_score=10, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T09:21:00.123456+00:00', modified_at=None, language='en')], total=3, page=1, page_size=20)" } diff --git a/tests/fixtures/parity/expected/account__library_no_match.json b/tests/fixtures/parity/expected/account__library_no_match.json index d628806..2184439 100644 --- a/tests/fixtures/parity/expected/account__library_no_match.json +++ b/tests/fixtures/parity/expected/account__library_no_match.json @@ -5,5 +5,12 @@ "page_size": 20, "total": 0 }, - "render_json": null + "dump_unset": { + "items": [], + "page": 1, + "page_size": 20, + "total": 0 + }, + "render_json": null, + "repr": "LibraryList(items=[], total=0, page=1, page_size=20)" } diff --git a/tests/fixtures/parity/expected/account__library_page_past_end.json b/tests/fixtures/parity/expected/account__library_page_past_end.json index 437be04..fc8bd17 100644 --- a/tests/fixtures/parity/expected/account__library_page_past_end.json +++ b/tests/fixtures/parity/expected/account__library_page_past_end.json @@ -5,5 +5,12 @@ "page_size": 20, "total": 1 }, - "render_json": null + "dump_unset": { + "items": [], + "page": 2, + "page_size": 20, + "total": 1 + }, + "render_json": null, + "repr": "LibraryList(items=[], total=1, page=2, page_size=20)" } diff --git a/tests/fixtures/parity/expected/account__library_paginated_second_page.json b/tests/fixtures/parity/expected/account__library_paginated_second_page.json index 6d4d3d3..e572a47 100644 --- a/tests/fixtures/parity/expected/account__library_paginated_second_page.json +++ b/tests/fixtures/parity/expected/account__library_paginated_second_page.json @@ -4,6 +4,21 @@ { "claim": "Paged claim 020.", "confidence": "low", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "domain": "", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + }, + { + "claim": "Paged claim 021.", + "confidence": "low", "created_at": "2026-10-01T09:14:00.123456+00:00", "domain": "", "entities": [], @@ -14,12 +29,34 @@ "modified_at": null, "suggested_rewrite": null, "verdict": "True", + "verification_id": "4d44dfaf" + } + ], + "page": 2, + "page_size": 20, + "total": 22 + }, + "dump_unset": { + "items": [ + { + "claim": "Paged claim 020.", + "confidence": "low", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "domain": "", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 10, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", "verification_id": "68ca4aaf" }, { "claim": "Paged claim 021.", "confidence": "low", - "created_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "domain": "", "entities": [], "executive_summary": "The claim is verified.", @@ -29,12 +66,13 @@ "modified_at": null, "suggested_rewrite": null, "verdict": "True", - "verification_id": "7c83247c" + "verification_id": "4d44dfaf" } ], "page": 2, "page_size": 20, "total": 22 }, - "render_json": null + "render_json": null, + "repr": "LibraryList(items=[LibraryItem(verification_id='68ca4aaf', claim='Paged claim 020.', domain='', entities=[], verdict='True', confidence='low', lenz_score=10, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en'), LibraryItem(verification_id='4d44dfaf', claim='Paged claim 021.', domain='', entities=[], verdict='True', confidence='low', lenz_score=10, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T09:14:00.123456+00:00', modified_at=None, language='en')], total=22, page=2, page_size=20)" } diff --git a/tests/fixtures/parity/expected/account__me_usage_extra_credits.json b/tests/fixtures/parity/expected/account__me_usage_extra_credits.json index 4b02079..3099e7d 100644 --- a/tests/fixtures/parity/expected/account__me_usage_extra_credits.json +++ b/tests/fixtures/parity/expected/account__me_usage_extra_credits.json @@ -35,7 +35,7 @@ "bonus": 250, "extra": 250, "remaining": 350, - "resets_at": "2026-10-01T09:07:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "total": 350, "used": 0 }, @@ -47,7 +47,65 @@ "has_webhook_secret": false, "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", + "verify": { + "bonus": 25, + "credits": 25, + "quota_remaining": 35, + "quota_total": 35, + "quota_used": 0, + "remaining": 35 + } + }, + "dump_unset": { + "ask": { + "bonus": 250, + "credits": 250, + "quota_remaining": 350, + "quota_total": 350, + "quota_used": 0, + "remaining": 350 + }, + "assess": { + "bonus": 250, + "credits": 250, + "quota_remaining": 350, + "quota_total": 350, + "quota_used": 0, + "remaining": 350 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 250, + "extra": 250, + "remaining": 350, + "resets_at": "2026-10-01T14:07:00+00:00", + "total": 350, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "verify": { "bonus": 25, "credits": 25, @@ -58,5 +116,6 @@ } }, "render": "Lenz usage (Free plan)\n 350 credits left (≈ 35 verifications · 350 assessments)\n Verify: 35 left (0 / 35 quota + 25 extra · 10 credits each · 5 at depth \"low\")\n Ask: 350 left (0 / 350 quota + 250 extra · 1 credit each)\n Assess: 350 left (0 / 350 quota + 250 extra · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", - "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 350,\n \"used\": 0,\n \"remaining\": 350,\n \"extra\": 250,\n \"bonus\": 250,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 35,\n \"quota_remaining\": 35,\n \"bonus\": 25,\n \"credits\": 25,\n \"remaining\": 35\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 350,\n \"quota_remaining\": 350,\n \"bonus\": 250,\n \"credits\": 250,\n \"remaining\": 350\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 350,\n \"quota_remaining\": 350,\n \"bonus\": 250,\n \"credits\": 250,\n \"remaining\": 350\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T14:07:00+00:00\",\n \"credits\": {\n \"total\": 350,\n \"used\": 0,\n \"remaining\": 350,\n \"extra\": 250,\n \"bonus\": 250,\n \"resets_at\": \"2026-10-01T14:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 35,\n \"quota_remaining\": 35,\n \"bonus\": 25,\n \"credits\": 25,\n \"remaining\": 35\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 350,\n \"quota_remaining\": 350,\n \"bonus\": 250,\n \"credits\": 250,\n \"remaining\": 350\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 350,\n \"quota_remaining\": 350,\n \"bonus\": 250,\n \"credits\": 250,\n \"remaining\": 350\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n", + "repr": "Usage(plan='free', plan_label='Free', quota_resets_at='2026-10-01T14:07:00+00:00', credits=UsageCredits(total=350, used=0, remaining=350, extra=250, bonus=250, resets_at='2026-10-01T14:07:00+00:00'), costs={'verify': 10, 'assess': 1, 'ask': 1, 'citation': 1, 'extract': 0}, cost_options={'verify': {'depth': {'standard': 10, 'low': 5}}}, verify=UsageCapacity(quota_used=0, quota_total=35, quota_remaining=35, bonus=25, credits=25, remaining=35), ask=UsageCapacity(quota_used=0, quota_total=350, quota_remaining=350, bonus=250, credits=250, remaining=350), assess=UsageCapacity(quota_used=0, quota_total=350, quota_remaining=350, bonus=250, credits=250, remaining=350), extract=UsageExtract(calls_today=0, daily_limit=1000, unlimited=False), has_webhook_secret=False)" } diff --git a/tests/fixtures/parity/expected/account__me_usage_extra_only.json b/tests/fixtures/parity/expected/account__me_usage_extra_only.json index fbd9a1f..e1f90b6 100644 --- a/tests/fixtures/parity/expected/account__me_usage_extra_only.json +++ b/tests/fixtures/parity/expected/account__me_usage_extra_only.json @@ -35,7 +35,7 @@ "bonus": 37, "extra": 37, "remaining": 37, - "resets_at": "2026-10-01T09:07:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "total": 137, "used": 100 }, @@ -47,7 +47,65 @@ "has_webhook_secret": false, "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", + "verify": { + "bonus": 3, + "credits": 3, + "quota_remaining": 3, + "quota_total": 13, + "quota_used": 10, + "remaining": 3 + } + }, + "dump_unset": { + "ask": { + "bonus": 37, + "credits": 37, + "quota_remaining": 37, + "quota_total": 137, + "quota_used": 100, + "remaining": 37 + }, + "assess": { + "bonus": 37, + "credits": 37, + "quota_remaining": 37, + "quota_total": 137, + "quota_used": 100, + "remaining": 37 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 37, + "extra": 37, + "remaining": 37, + "resets_at": "2026-10-01T14:07:00+00:00", + "total": 137, + "used": 100 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "verify": { "bonus": 3, "credits": 3, @@ -58,5 +116,6 @@ } }, "render": "Lenz usage (Free plan)\n 37 credits left (≈ 3 verifications · 37 assessments)\n Verify: 3 left (10 / 13 quota + 3 extra · 10 credits each · 5 at depth \"low\")\n Ask: 37 left (100 / 137 quota + 37 extra · 1 credit each)\n Assess: 37 left (100 / 137 quota + 37 extra · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", - "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 137,\n \"used\": 100,\n \"remaining\": 37,\n \"extra\": 37,\n \"bonus\": 37,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 10,\n \"quota_total\": 13,\n \"quota_remaining\": 3,\n \"bonus\": 3,\n \"credits\": 3,\n \"remaining\": 3\n },\n \"ask\": {\n \"quota_used\": 100,\n \"quota_total\": 137,\n \"quota_remaining\": 37,\n \"bonus\": 37,\n \"credits\": 37,\n \"remaining\": 37\n },\n \"assess\": {\n \"quota_used\": 100,\n \"quota_total\": 137,\n \"quota_remaining\": 37,\n \"bonus\": 37,\n \"credits\": 37,\n \"remaining\": 37\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T14:07:00+00:00\",\n \"credits\": {\n \"total\": 137,\n \"used\": 100,\n \"remaining\": 37,\n \"extra\": 37,\n \"bonus\": 37,\n \"resets_at\": \"2026-10-01T14:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 10,\n \"quota_total\": 13,\n \"quota_remaining\": 3,\n \"bonus\": 3,\n \"credits\": 3,\n \"remaining\": 3\n },\n \"ask\": {\n \"quota_used\": 100,\n \"quota_total\": 137,\n \"quota_remaining\": 37,\n \"bonus\": 37,\n \"credits\": 37,\n \"remaining\": 37\n },\n \"assess\": {\n \"quota_used\": 100,\n \"quota_total\": 137,\n \"quota_remaining\": 37,\n \"bonus\": 37,\n \"credits\": 37,\n \"remaining\": 37\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n", + "repr": "Usage(plan='free', plan_label='Free', quota_resets_at='2026-10-01T14:07:00+00:00', credits=UsageCredits(total=137, used=100, remaining=37, extra=37, bonus=37, resets_at='2026-10-01T14:07:00+00:00'), costs={'verify': 10, 'assess': 1, 'ask': 1, 'citation': 1, 'extract': 0}, cost_options={'verify': {'depth': {'standard': 10, 'low': 5}}}, verify=UsageCapacity(quota_used=10, quota_total=13, quota_remaining=3, bonus=3, credits=3, remaining=3), ask=UsageCapacity(quota_used=100, quota_total=137, quota_remaining=37, bonus=37, credits=37, remaining=37), assess=UsageCapacity(quota_used=100, quota_total=137, quota_remaining=37, bonus=37, credits=37, remaining=37), extract=UsageExtract(calls_today=0, daily_limit=1000, unlimited=False), has_webhook_secret=False)" } diff --git a/tests/fixtures/parity/expected/account__me_usage_extract_calls.json b/tests/fixtures/parity/expected/account__me_usage_extract_calls.json index cfb8de5..5cfc97c 100644 --- a/tests/fixtures/parity/expected/account__me_usage_extract_calls.json +++ b/tests/fixtures/parity/expected/account__me_usage_extract_calls.json @@ -35,7 +35,7 @@ "bonus": 0, "extra": 0, "remaining": 100, - "resets_at": "2026-10-01T09:07:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "total": 100, "used": 0 }, @@ -47,7 +47,65 @@ "has_webhook_secret": false, "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 10, + "quota_total": 10, + "quota_used": 0, + "remaining": 10 + } + }, + "dump_unset": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 100, + "resets_at": "2026-10-01T14:07:00+00:00", + "total": 100, + "used": 0 + }, + "extract": { + "calls_today": 7, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "verify": { "bonus": 0, "credits": 0, @@ -58,5 +116,6 @@ } }, "render": "Lenz usage (Free plan)\n 100 credits left (≈ 10 verifications · 100 assessments)\n Verify: 10 left (0 / 10 quota · 10 credits each · 5 at depth \"low\")\n Ask: 100 left (0 / 100 quota · 1 credit each)\n Assess: 100 left (0 / 100 quota · 1 credit each)\n Extract: 7 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", - "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 0,\n \"remaining\": 100,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 10,\n \"quota_remaining\": 10,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 10\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"extract\": {\n \"calls_today\": 7,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T14:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 0,\n \"remaining\": 100,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T14:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 10,\n \"quota_remaining\": 10,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 10\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"extract\": {\n \"calls_today\": 7,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n", + "repr": "Usage(plan='free', plan_label='Free', quota_resets_at='2026-10-01T14:07:00+00:00', credits=UsageCredits(total=100, used=0, remaining=100, extra=0, bonus=0, resets_at='2026-10-01T14:07:00+00:00'), costs={'verify': 10, 'assess': 1, 'ask': 1, 'citation': 1, 'extract': 0}, cost_options={'verify': {'depth': {'standard': 10, 'low': 5}}}, verify=UsageCapacity(quota_used=0, quota_total=10, quota_remaining=10, bonus=0, credits=0, remaining=10), ask=UsageCapacity(quota_used=0, quota_total=100, quota_remaining=100, bonus=0, credits=0, remaining=100), assess=UsageCapacity(quota_used=0, quota_total=100, quota_remaining=100, bonus=0, credits=0, remaining=100), extract=UsageExtract(calls_today=7, daily_limit=1000, unlimited=False), has_webhook_secret=False)" } diff --git a/tests/fixtures/parity/expected/account__me_usage_free.json b/tests/fixtures/parity/expected/account__me_usage_free.json index 5d7b08d..f2f3166 100644 --- a/tests/fixtures/parity/expected/account__me_usage_free.json +++ b/tests/fixtures/parity/expected/account__me_usage_free.json @@ -35,7 +35,7 @@ "bonus": 0, "extra": 0, "remaining": 100, - "resets_at": "2026-10-01T09:07:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "total": 100, "used": 0 }, @@ -47,7 +47,65 @@ "has_webhook_secret": false, "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 10, + "quota_total": 10, + "quota_used": 0, + "remaining": 10 + } + }, + "dump_unset": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 100, + "resets_at": "2026-10-01T14:07:00+00:00", + "total": 100, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "verify": { "bonus": 0, "credits": 0, @@ -58,5 +116,6 @@ } }, "render": "Lenz usage (Free plan)\n 100 credits left (≈ 10 verifications · 100 assessments)\n Verify: 10 left (0 / 10 quota · 10 credits each · 5 at depth \"low\")\n Ask: 100 left (0 / 100 quota · 1 credit each)\n Assess: 100 left (0 / 100 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", - "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 0,\n \"remaining\": 100,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 10,\n \"quota_remaining\": 10,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 10\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T14:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 0,\n \"remaining\": 100,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T14:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 10,\n \"quota_remaining\": 10,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 10\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n", + "repr": "Usage(plan='free', plan_label='Free', quota_resets_at='2026-10-01T14:07:00+00:00', credits=UsageCredits(total=100, used=0, remaining=100, extra=0, bonus=0, resets_at='2026-10-01T14:07:00+00:00'), costs={'verify': 10, 'assess': 1, 'ask': 1, 'citation': 1, 'extract': 0}, cost_options={'verify': {'depth': {'standard': 10, 'low': 5}}}, verify=UsageCapacity(quota_used=0, quota_total=10, quota_remaining=10, bonus=0, credits=0, remaining=10), ask=UsageCapacity(quota_used=0, quota_total=100, quota_remaining=100, bonus=0, credits=0, remaining=100), assess=UsageCapacity(quota_used=0, quota_total=100, quota_remaining=100, bonus=0, credits=0, remaining=100), extract=UsageExtract(calls_today=0, daily_limit=1000, unlimited=False), has_webhook_secret=False)" } diff --git a/tests/fixtures/parity/expected/account__me_usage_free_partly_spent.json b/tests/fixtures/parity/expected/account__me_usage_free_partly_spent.json index 61b0e4c..d353d1e 100644 --- a/tests/fixtures/parity/expected/account__me_usage_free_partly_spent.json +++ b/tests/fixtures/parity/expected/account__me_usage_free_partly_spent.json @@ -35,7 +35,7 @@ "bonus": 0, "extra": 0, "remaining": 83, - "resets_at": "2026-10-01T09:07:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "total": 100, "used": 17 }, @@ -47,7 +47,65 @@ "has_webhook_secret": false, "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 8, + "quota_total": 10, + "quota_used": 2, + "remaining": 8 + } + }, + "dump_unset": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 83, + "quota_total": 100, + "quota_used": 17, + "remaining": 83 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 83, + "quota_total": 100, + "quota_used": 17, + "remaining": 83 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 83, + "resets_at": "2026-10-01T14:07:00+00:00", + "total": 100, + "used": 17 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "verify": { "bonus": 0, "credits": 0, @@ -58,5 +116,6 @@ } }, "render": "Lenz usage (Free plan)\n 83 credits left (≈ 8 verifications · 83 assessments)\n Verify: 8 left (2 / 10 quota · 10 credits each · 5 at depth \"low\")\n Ask: 83 left (17 / 100 quota · 1 credit each)\n Assess: 83 left (17 / 100 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", - "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 17,\n \"remaining\": 83,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 2,\n \"quota_total\": 10,\n \"quota_remaining\": 8,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 8\n },\n \"ask\": {\n \"quota_used\": 17,\n \"quota_total\": 100,\n \"quota_remaining\": 83,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 83\n },\n \"assess\": {\n \"quota_used\": 17,\n \"quota_total\": 100,\n \"quota_remaining\": 83,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 83\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T14:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 17,\n \"remaining\": 83,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T14:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 2,\n \"quota_total\": 10,\n \"quota_remaining\": 8,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 8\n },\n \"ask\": {\n \"quota_used\": 17,\n \"quota_total\": 100,\n \"quota_remaining\": 83,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 83\n },\n \"assess\": {\n \"quota_used\": 17,\n \"quota_total\": 100,\n \"quota_remaining\": 83,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 83\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n", + "repr": "Usage(plan='free', plan_label='Free', quota_resets_at='2026-10-01T14:07:00+00:00', credits=UsageCredits(total=100, used=17, remaining=83, extra=0, bonus=0, resets_at='2026-10-01T14:07:00+00:00'), costs={'verify': 10, 'assess': 1, 'ask': 1, 'citation': 1, 'extract': 0}, cost_options={'verify': {'depth': {'standard': 10, 'low': 5}}}, verify=UsageCapacity(quota_used=2, quota_total=10, quota_remaining=8, bonus=0, credits=0, remaining=8), ask=UsageCapacity(quota_used=17, quota_total=100, quota_remaining=83, bonus=0, credits=0, remaining=83), assess=UsageCapacity(quota_used=17, quota_total=100, quota_remaining=83, bonus=0, credits=0, remaining=83), extract=UsageExtract(calls_today=0, daily_limit=1000, unlimited=False), has_webhook_secret=False)" } diff --git a/tests/fixtures/parity/expected/account__me_usage_oauth.json b/tests/fixtures/parity/expected/account__me_usage_oauth.json new file mode 100644 index 0000000..f2f3166 --- /dev/null +++ b/tests/fixtures/parity/expected/account__me_usage_oauth.json @@ -0,0 +1,121 @@ +{ + "dump": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 100, + "resets_at": "2026-10-01T14:07:00+00:00", + "total": 100, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T14:07:00+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 10, + "quota_total": 10, + "quota_used": 0, + "remaining": 10 + } + }, + "dump_unset": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 100, + "resets_at": "2026-10-01T14:07:00+00:00", + "total": 100, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T14:07:00+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 10, + "quota_total": 10, + "quota_used": 0, + "remaining": 10 + } + }, + "render": "Lenz usage (Free plan)\n 100 credits left (≈ 10 verifications · 100 assessments)\n Verify: 10 left (0 / 10 quota · 10 credits each · 5 at depth \"low\")\n Ask: 100 left (0 / 100 quota · 1 credit each)\n Assess: 100 left (0 / 100 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T14:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 0,\n \"remaining\": 100,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T14:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 10,\n \"quota_remaining\": 10,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 10\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n", + "repr": "Usage(plan='free', plan_label='Free', quota_resets_at='2026-10-01T14:07:00+00:00', credits=UsageCredits(total=100, used=0, remaining=100, extra=0, bonus=0, resets_at='2026-10-01T14:07:00+00:00'), costs={'verify': 10, 'assess': 1, 'ask': 1, 'citation': 1, 'extract': 0}, cost_options={'verify': {'depth': {'standard': 10, 'low': 5}}}, verify=UsageCapacity(quota_used=0, quota_total=10, quota_remaining=10, bonus=0, credits=0, remaining=10), ask=UsageCapacity(quota_used=0, quota_total=100, quota_remaining=100, bonus=0, credits=0, remaining=100), assess=UsageCapacity(quota_used=0, quota_total=100, quota_remaining=100, bonus=0, credits=0, remaining=100), extract=UsageExtract(calls_today=0, daily_limit=1000, unlimited=False), has_webhook_secret=False)" +} diff --git a/tests/fixtures/parity/expected/account__me_usage_plus.json b/tests/fixtures/parity/expected/account__me_usage_plus.json index 240dcb2..faadaf1 100644 --- a/tests/fixtures/parity/expected/account__me_usage_plus.json +++ b/tests/fixtures/parity/expected/account__me_usage_plus.json @@ -35,7 +35,7 @@ "bonus": 0, "extra": 0, "remaining": 500, - "resets_at": "2026-10-01T09:07:00.123456+00:00", + "resets_at": "2026-10-01T14:07:00.123456+00:00", "total": 500, "used": 0 }, @@ -47,7 +47,65 @@ "has_webhook_secret": false, "plan": "plus", "plan_label": "Plus", - "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "quota_resets_at": "2026-10-01T14:07:00.123456+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 50, + "quota_total": 50, + "quota_used": 0, + "remaining": 50 + } + }, + "dump_unset": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 500, + "quota_total": 500, + "quota_used": 0, + "remaining": 500 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 500, + "quota_total": 500, + "quota_used": 0, + "remaining": 500 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 500, + "resets_at": "2026-10-01T14:07:00.123456+00:00", + "total": 500, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "plus", + "plan_label": "Plus", + "quota_resets_at": "2026-10-01T14:07:00.123456+00:00", "verify": { "bonus": 0, "credits": 0, @@ -58,5 +116,6 @@ } }, "render": "Lenz usage (Plus plan)\n 500 credits left (≈ 50 verifications · 500 assessments)\n Verify: 50 left (0 / 50 quota · 10 credits each · 5 at depth \"low\")\n Ask: 500 left (0 / 500 quota · 1 credit each)\n Assess: 500 left (0 / 500 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", - "render_json": "{\n \"plan\": \"plus\",\n \"plan_label\": \"Plus\",\n \"quota_resets_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"credits\": {\n \"total\": 500,\n \"used\": 0,\n \"remaining\": 500,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00.123456+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 50,\n \"quota_remaining\": 50,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 50\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 500,\n \"quota_remaining\": 500,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 500\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 500,\n \"quota_remaining\": 500,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 500\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" + "render_json": "{\n \"plan\": \"plus\",\n \"plan_label\": \"Plus\",\n \"quota_resets_at\": \"2026-10-01T14:07:00.123456+00:00\",\n \"credits\": {\n \"total\": 500,\n \"used\": 0,\n \"remaining\": 500,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T14:07:00.123456+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 50,\n \"quota_remaining\": 50,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 50\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 500,\n \"quota_remaining\": 500,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 500\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 500,\n \"quota_remaining\": 500,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 500\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n", + "repr": "Usage(plan='plus', plan_label='Plus', quota_resets_at='2026-10-01T14:07:00.123456+00:00', credits=UsageCredits(total=500, used=0, remaining=500, extra=0, bonus=0, resets_at='2026-10-01T14:07:00.123456+00:00'), costs={'verify': 10, 'assess': 1, 'ask': 1, 'citation': 1, 'extract': 0}, cost_options={'verify': {'depth': {'standard': 10, 'low': 5}}}, verify=UsageCapacity(quota_used=0, quota_total=50, quota_remaining=50, bonus=0, credits=0, remaining=50), ask=UsageCapacity(quota_used=0, quota_total=500, quota_remaining=500, bonus=0, credits=0, remaining=500), assess=UsageCapacity(quota_used=0, quota_total=500, quota_remaining=500, bonus=0, credits=0, remaining=500), extract=UsageExtract(calls_today=0, daily_limit=1000, unlimited=False), has_webhook_secret=False)" } diff --git a/tests/fixtures/parity/expected/account__me_usage_pro.json b/tests/fixtures/parity/expected/account__me_usage_pro.json index 6bd10f7..17433cd 100644 --- a/tests/fixtures/parity/expected/account__me_usage_pro.json +++ b/tests/fixtures/parity/expected/account__me_usage_pro.json @@ -35,7 +35,7 @@ "bonus": 0, "extra": 0, "remaining": 5000, - "resets_at": "2026-10-01T09:07:00.123456+00:00", + "resets_at": "2026-10-01T14:07:00.123456+00:00", "total": 5000, "used": 0 }, @@ -47,7 +47,65 @@ "has_webhook_secret": false, "plan": "pro", "plan_label": "Pro", - "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "quota_resets_at": "2026-10-01T14:07:00.123456+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 500, + "quota_total": 500, + "quota_used": 0, + "remaining": 500 + } + }, + "dump_unset": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 5000, + "quota_total": 5000, + "quota_used": 0, + "remaining": 5000 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 5000, + "quota_total": 5000, + "quota_used": 0, + "remaining": 5000 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 5000, + "resets_at": "2026-10-01T14:07:00.123456+00:00", + "total": 5000, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "pro", + "plan_label": "Pro", + "quota_resets_at": "2026-10-01T14:07:00.123456+00:00", "verify": { "bonus": 0, "credits": 0, @@ -58,5 +116,6 @@ } }, "render": "Lenz usage (Pro plan)\n 5000 credits left (≈ 500 verifications · 5000 assessments)\n Verify: 500 left (0 / 500 quota · 10 credits each · 5 at depth \"low\")\n Ask: 5000 left (0 / 5000 quota · 1 credit each)\n Assess: 5000 left (0 / 5000 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", - "render_json": "{\n \"plan\": \"pro\",\n \"plan_label\": \"Pro\",\n \"quota_resets_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"credits\": {\n \"total\": 5000,\n \"used\": 0,\n \"remaining\": 5000,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00.123456+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 500,\n \"quota_remaining\": 500,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 500\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 5000,\n \"quota_remaining\": 5000,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 5000\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 5000,\n \"quota_remaining\": 5000,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 5000\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" + "render_json": "{\n \"plan\": \"pro\",\n \"plan_label\": \"Pro\",\n \"quota_resets_at\": \"2026-10-01T14:07:00.123456+00:00\",\n \"credits\": {\n \"total\": 5000,\n \"used\": 0,\n \"remaining\": 5000,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T14:07:00.123456+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 500,\n \"quota_remaining\": 500,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 500\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 5000,\n \"quota_remaining\": 5000,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 5000\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 5000,\n \"quota_remaining\": 5000,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 5000\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n", + "repr": "Usage(plan='pro', plan_label='Pro', quota_resets_at='2026-10-01T14:07:00.123456+00:00', credits=UsageCredits(total=5000, used=0, remaining=5000, extra=0, bonus=0, resets_at='2026-10-01T14:07:00.123456+00:00'), costs={'verify': 10, 'assess': 1, 'ask': 1, 'citation': 1, 'extract': 0}, cost_options={'verify': {'depth': {'standard': 10, 'low': 5}}}, verify=UsageCapacity(quota_used=0, quota_total=500, quota_remaining=500, bonus=0, credits=0, remaining=500), ask=UsageCapacity(quota_used=0, quota_total=5000, quota_remaining=5000, bonus=0, credits=0, remaining=5000), assess=UsageCapacity(quota_used=0, quota_total=5000, quota_remaining=5000, bonus=0, credits=0, remaining=5000), extract=UsageExtract(calls_today=0, daily_limit=1000, unlimited=False), has_webhook_secret=False)" } diff --git a/tests/fixtures/parity/expected/account__me_usage_pro_extra.json b/tests/fixtures/parity/expected/account__me_usage_pro_extra.json index ca22ae7..99126d3 100644 --- a/tests/fixtures/parity/expected/account__me_usage_pro_extra.json +++ b/tests/fixtures/parity/expected/account__me_usage_pro_extra.json @@ -35,7 +35,7 @@ "bonus": 1000, "extra": 1000, "remaining": 6000, - "resets_at": "2026-10-01T09:07:00.123456+00:00", + "resets_at": "2026-10-01T14:07:00.123456+00:00", "total": 6000, "used": 0 }, @@ -47,7 +47,65 @@ "has_webhook_secret": false, "plan": "pro", "plan_label": "Pro", - "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "quota_resets_at": "2026-10-01T14:07:00.123456+00:00", + "verify": { + "bonus": 100, + "credits": 100, + "quota_remaining": 600, + "quota_total": 600, + "quota_used": 0, + "remaining": 600 + } + }, + "dump_unset": { + "ask": { + "bonus": 1000, + "credits": 1000, + "quota_remaining": 6000, + "quota_total": 6000, + "quota_used": 0, + "remaining": 6000 + }, + "assess": { + "bonus": 1000, + "credits": 1000, + "quota_remaining": 6000, + "quota_total": 6000, + "quota_used": 0, + "remaining": 6000 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 1000, + "extra": 1000, + "remaining": 6000, + "resets_at": "2026-10-01T14:07:00.123456+00:00", + "total": 6000, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "pro", + "plan_label": "Pro", + "quota_resets_at": "2026-10-01T14:07:00.123456+00:00", "verify": { "bonus": 100, "credits": 100, @@ -58,5 +116,6 @@ } }, "render": "Lenz usage (Pro plan)\n 6000 credits left (≈ 600 verifications · 6000 assessments)\n Verify: 600 left (0 / 600 quota + 100 extra · 10 credits each · 5 at depth \"low\")\n Ask: 6000 left (0 / 6000 quota + 1000 extra · 1 credit each)\n Assess: 6000 left (0 / 6000 quota + 1000 extra · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", - "render_json": "{\n \"plan\": \"pro\",\n \"plan_label\": \"Pro\",\n \"quota_resets_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"credits\": {\n \"total\": 6000,\n \"used\": 0,\n \"remaining\": 6000,\n \"extra\": 1000,\n \"bonus\": 1000,\n \"resets_at\": \"2026-10-01T09:07:00.123456+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 600,\n \"quota_remaining\": 600,\n \"bonus\": 100,\n \"credits\": 100,\n \"remaining\": 600\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 6000,\n \"quota_remaining\": 6000,\n \"bonus\": 1000,\n \"credits\": 1000,\n \"remaining\": 6000\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 6000,\n \"quota_remaining\": 6000,\n \"bonus\": 1000,\n \"credits\": 1000,\n \"remaining\": 6000\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" + "render_json": "{\n \"plan\": \"pro\",\n \"plan_label\": \"Pro\",\n \"quota_resets_at\": \"2026-10-01T14:07:00.123456+00:00\",\n \"credits\": {\n \"total\": 6000,\n \"used\": 0,\n \"remaining\": 6000,\n \"extra\": 1000,\n \"bonus\": 1000,\n \"resets_at\": \"2026-10-01T14:07:00.123456+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 600,\n \"quota_remaining\": 600,\n \"bonus\": 100,\n \"credits\": 100,\n \"remaining\": 600\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 6000,\n \"quota_remaining\": 6000,\n \"bonus\": 1000,\n \"credits\": 1000,\n \"remaining\": 6000\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 6000,\n \"quota_remaining\": 6000,\n \"bonus\": 1000,\n \"credits\": 1000,\n \"remaining\": 6000\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n", + "repr": "Usage(plan='pro', plan_label='Pro', quota_resets_at='2026-10-01T14:07:00.123456+00:00', credits=UsageCredits(total=6000, used=0, remaining=6000, extra=1000, bonus=1000, resets_at='2026-10-01T14:07:00.123456+00:00'), costs={'verify': 10, 'assess': 1, 'ask': 1, 'citation': 1, 'extract': 0}, cost_options={'verify': {'depth': {'standard': 10, 'low': 5}}}, verify=UsageCapacity(quota_used=0, quota_total=600, quota_remaining=600, bonus=100, credits=100, remaining=600), ask=UsageCapacity(quota_used=0, quota_total=6000, quota_remaining=6000, bonus=1000, credits=1000, remaining=6000), assess=UsageCapacity(quota_used=0, quota_total=6000, quota_remaining=6000, bonus=1000, credits=1000, remaining=6000), extract=UsageExtract(calls_today=0, daily_limit=1000, unlimited=False), has_webhook_secret=False)" } diff --git a/tests/fixtures/parity/expected/account__me_usage_stale_quota_row.json b/tests/fixtures/parity/expected/account__me_usage_stale_quota_row.json index 5d7b08d..f2f3166 100644 --- a/tests/fixtures/parity/expected/account__me_usage_stale_quota_row.json +++ b/tests/fixtures/parity/expected/account__me_usage_stale_quota_row.json @@ -35,7 +35,7 @@ "bonus": 0, "extra": 0, "remaining": 100, - "resets_at": "2026-10-01T09:07:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "total": 100, "used": 0 }, @@ -47,7 +47,65 @@ "has_webhook_secret": false, "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", + "verify": { + "bonus": 0, + "credits": 0, + "quota_remaining": 10, + "quota_total": 10, + "quota_used": 0, + "remaining": 10 + } + }, + "dump_unset": { + "ask": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "assess": { + "bonus": 0, + "credits": 0, + "quota_remaining": 100, + "quota_total": 100, + "quota_used": 0, + "remaining": 100 + }, + "cost_options": { + "verify": { + "depth": { + "low": 5, + "standard": 10 + } + } + }, + "costs": { + "ask": 1, + "assess": 1, + "citation": 1, + "extract": 0, + "verify": 10 + }, + "credits": { + "bonus": 0, + "extra": 0, + "remaining": 100, + "resets_at": "2026-10-01T14:07:00+00:00", + "total": 100, + "used": 0 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false, + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "verify": { "bonus": 0, "credits": 0, @@ -58,5 +116,6 @@ } }, "render": "Lenz usage (Free plan)\n 100 credits left (≈ 10 verifications · 100 assessments)\n Verify: 10 left (0 / 10 quota · 10 credits each · 5 at depth \"low\")\n Ask: 100 left (0 / 100 quota · 1 credit each)\n Assess: 100 left (0 / 100 quota · 1 credit each)\n Extract: 0 / 1000 today (free — no credit charge)\n Credits reset Oct 1, 2026\n", - "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T09:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 0,\n \"remaining\": 100,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T09:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 10,\n \"quota_remaining\": 10,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 10\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n" + "render_json": "{\n \"plan\": \"free\",\n \"plan_label\": \"Free\",\n \"quota_resets_at\": \"2026-10-01T14:07:00+00:00\",\n \"credits\": {\n \"total\": 100,\n \"used\": 0,\n \"remaining\": 100,\n \"extra\": 0,\n \"bonus\": 0,\n \"resets_at\": \"2026-10-01T14:07:00+00:00\"\n },\n \"costs\": {\n \"verify\": 10,\n \"assess\": 1,\n \"ask\": 1,\n \"citation\": 1,\n \"extract\": 0\n },\n \"cost_options\": {\n \"verify\": {\n \"depth\": {\n \"standard\": 10,\n \"low\": 5\n }\n }\n },\n \"verify\": {\n \"quota_used\": 0,\n \"quota_total\": 10,\n \"quota_remaining\": 10,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 10\n },\n \"ask\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"assess\": {\n \"quota_used\": 0,\n \"quota_total\": 100,\n \"quota_remaining\": 100,\n \"bonus\": 0,\n \"credits\": 0,\n \"remaining\": 100\n },\n \"extract\": {\n \"calls_today\": 0,\n \"daily_limit\": 1000,\n \"unlimited\": false\n },\n \"has_webhook_secret\": false\n}\n", + "repr": "Usage(plan='free', plan_label='Free', quota_resets_at='2026-10-01T14:07:00+00:00', credits=UsageCredits(total=100, used=0, remaining=100, extra=0, bonus=0, resets_at='2026-10-01T14:07:00+00:00'), costs={'verify': 10, 'assess': 1, 'ask': 1, 'citation': 1, 'extract': 0}, cost_options={'verify': {'depth': {'standard': 10, 'low': 5}}}, verify=UsageCapacity(quota_used=0, quota_total=10, quota_remaining=10, bonus=0, credits=0, remaining=10), ask=UsageCapacity(quota_used=0, quota_total=100, quota_remaining=100, bonus=0, credits=0, remaining=100), assess=UsageCapacity(quota_used=0, quota_total=100, quota_remaining=100, bonus=0, credits=0, remaining=100), extract=UsageExtract(calls_today=0, daily_limit=1000, unlimited=False), has_webhook_secret=False)" } diff --git a/tests/fixtures/parity/expected/account__oauth_register_success.json b/tests/fixtures/parity/expected/account__oauth_register_success.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__oauth_register_success.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__oauth_revoke.json b/tests/fixtures/parity/expected/account__oauth_revoke.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__oauth_revoke.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__oauth_revoke_token.json b/tests/fixtures/parity/expected/account__oauth_revoke_token.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__oauth_revoke_token.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/account__webhook_secret_api_key.json b/tests/fixtures/parity/expected/account__webhook_secret_api_key.json new file mode 100644 index 0000000..99f0634 --- /dev/null +++ b/tests/fixtures/parity/expected/account__webhook_secret_api_key.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.", + "code": "oauth_only", + "doc_url": "https://lenz.io/docs/auth", + "fix": "This key doesn't have access to that resource.", + "friendly_text": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.\n Fix: This key doesn't have access to that resource.", + "message": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "This key doesn't have access to that resource.", + "message": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.", + "status": 403 + } + }, + "request_id": "", + "status_code": 403, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/account__webhook_secret_insufficient_scope.json b/tests/fixtures/parity/expected/account__webhook_secret_insufficient_scope.json new file mode 100644 index 0000000..567f3ae --- /dev/null +++ b/tests/fixtures/parity/expected/account__webhook_secret_insufficient_scope.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "The access token does not allow this call.", + "code": "insufficient_scope", + "doc_url": "https://lenz.io/docs/auth", + "fix": "This key doesn't have access to that resource.", + "friendly_text": "The access token does not allow this call.\n Fix: This key doesn't have access to that resource.", + "message": "The access token does not allow this call.", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "This key doesn't have access to that resource.", + "message": "The access token does not allow this call.", + "status": 403 + } + }, + "request_id": "", + "status_code": 403, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/account__webhook_secret_oauth.json b/tests/fixtures/parity/expected/account__webhook_secret_oauth.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/fixtures/parity/expected/account__webhook_secret_oauth.json @@ -0,0 +1 @@ +{} diff --git a/tests/fixtures/parity/expected/assess__402_no_credits.json b/tests/fixtures/parity/expected/assess__402_no_credits.json index 732bc39..91af7cd 100644 --- a/tests/fixtures/parity/expected/assess__402_no_credits.json +++ b/tests/fixtures/parity/expected/assess__402_no_credits.json @@ -20,7 +20,7 @@ "remaining": 0, "request_id": "", "requested": null, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "status_code": 402, "type": "LenzQuotaExceededError", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" diff --git a/tests/fixtures/parity/expected/assess__deep_tier_hit.json b/tests/fixtures/parity/expected/assess__deep_tier_hit.json index 89424ff..2964620 100644 --- a/tests/fixtures/parity/expected/assess__deep_tier_hit.json +++ b/tests/fixtures/parity/expected/assess__deep_tier_hit.json @@ -21,6 +21,27 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "Water boils at 100C.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": "The claim is verified.", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": "https://lenz.io/api/v1/verifications/f3436f50" + } + ], + "error": null, + "more_claims": [] + }, "render": "True (high) — Water boils at 100C.\n The claim is verified.\n ask follow-ups: lenz ask f3436f50 \"\"\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Water boils at 100C.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": \"https://lenz.io/api/v1/verifications/f3436f50\",\n \"rationale\": \"The claim is verified.\",\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Water boils at 100C.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": \"https://lenz.io/api/v1/verifications/f3436f50\",\n \"rationale\": \"The claim is verified.\",\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='Water boils at 100C.', language='en', verdict='True', confidence='high', verification_url='https://lenz.io/api/v1/verifications/f3436f50', rationale='The claim is verified.', dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None)], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__idempotency_first.json b/tests/fixtures/parity/expected/assess__idempotency_first.json index cb3d6d5..614661f 100644 --- a/tests/fixtures/parity/expected/assess__idempotency_first.json +++ b/tests/fixtures/parity/expected/assess__idempotency_first.json @@ -21,6 +21,27 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "The Earth orbits the Sun.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "more_claims": [] + }, "render": "True (high) — The Earth orbits the Sun.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Earth orbits the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Earth orbits the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='The Earth orbits the Sun.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None)], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__idempotency_replay.json b/tests/fixtures/parity/expected/assess__idempotency_replay.json index cb3d6d5..614661f 100644 --- a/tests/fixtures/parity/expected/assess__idempotency_replay.json +++ b/tests/fixtures/parity/expected/assess__idempotency_replay.json @@ -21,6 +21,27 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "The Earth orbits the Sun.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "more_claims": [] + }, "render": "True (high) — The Earth orbits the Sun.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Earth orbits the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Earth orbits the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='The Earth orbits the Sun.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None)], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__list_all_error_rows.json b/tests/fixtures/parity/expected/assess__list_all_error_rows.json index edf8955..5617abd 100644 --- a/tests/fixtures/parity/expected/assess__list_all_error_rows.json +++ b/tests/fixtures/parity/expected/assess__list_all_error_rows.json @@ -35,6 +35,41 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "hi", + "confidence": "low", + "dissent": null, + "error_code": "no_claim", + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.", + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Error", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "hello", + "confidence": "low", + "dissent": null, + "error_code": "no_claim", + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.", + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Error", + "verification_url": null + } + ], + "error": null, + "more_claims": [] + }, "render": "Error (no_claim) — hi\n The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\nError (no_claim) — hello\n The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"hi\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\"\n },\n {\n \"claim\": \"hello\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\"\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"hi\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\"\n },\n {\n \"claim\": \"hello\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\"\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='hi', language='en', verdict='Error', confidence='low', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code='no_claim', candidate_claims=[], identified_claims=[], hint='The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.'), AssessClaim(claim='hello', language='en', verdict='Error', confidence='low', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code='no_claim', candidate_claims=[], identified_claims=[], hint='The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.')], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__list_compound_item.json b/tests/fixtures/parity/expected/assess__list_compound_item.json index 6437e79..550432b 100644 --- a/tests/fixtures/parity/expected/assess__list_compound_item.json +++ b/tests/fixtures/parity/expected/assess__list_compound_item.json @@ -38,6 +38,44 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "Primary claim.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": "Assessed the main claim only. Send identified_claims as their own items to check the rest.", + "identified_claims": [ + "Second claim.", + "Third claim." + ], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Mostly False", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "A plain claim.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Mostly False", + "verification_url": null + } + ], + "error": null, + "more_claims": [] + }, "render": "Mostly False (high) — Primary claim.\n also found:\n • Second claim.\n • Third claim.\n Assessed the main claim only. Send identified_claims as their own items to check the rest.\nMostly False (high) — A plain claim.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Primary claim.\",\n \"language\": \"en\",\n \"verdict\": \"Mostly False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [\n \"Second claim.\",\n \"Third claim.\"\n ],\n \"hint\": \"Assessed the main claim only. Send identified_claims as their own items to check the rest.\"\n },\n {\n \"claim\": \"A plain claim.\",\n \"language\": \"en\",\n \"verdict\": \"Mostly False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Primary claim.\",\n \"language\": \"en\",\n \"verdict\": \"Mostly False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [\n \"Second claim.\",\n \"Third claim.\"\n ],\n \"hint\": \"Assessed the main claim only. Send identified_claims as their own items to check the rest.\"\n },\n {\n \"claim\": \"A plain claim.\",\n \"language\": \"en\",\n \"verdict\": \"Mostly False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='Primary claim.', language='en', verdict='Mostly False', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=['Second claim.', 'Third claim.'], hint='Assessed the main claim only. Send identified_claims as their own items to check the rest.'), AssessClaim(claim='A plain claim.', language='en', verdict='Mostly False', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None)], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__list_mixed_rows.json b/tests/fixtures/parity/expected/assess__list_mixed_rows.json index f92df93..edb640a 100644 --- a/tests/fixtures/parity/expected/assess__list_mixed_rows.json +++ b/tests/fixtures/parity/expected/assess__list_mixed_rows.json @@ -63,6 +63,69 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "Water boils at 100 C at sea level.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "hello there", + "confidence": "low", + "dissent": null, + "error_code": "no_claim", + "hint": "The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.", + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Error", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "vendor is down", + "confidence": "low", + "dissent": null, + "error_code": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Error", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "cannot frame", + "confidence": "low", + "dissent": null, + "error_code": "framing_failed", + "hint": "This item could not be processed; retrying it as-is will not help. Send it rephrased as one factual statement; nothing was charged.", + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Error", + "verification_url": null + } + ], + "error": null, + "more_claims": [] + }, "render": "True (high) — Water boils at 100 C at sea level.\nError (no_claim) — hello there\n The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\nError (upstream_unavailable) — vendor is down\n A model provider was unavailable for this item. Retry it; nothing was charged.\nError (framing_failed) — cannot frame\n This item could not be processed; retrying it as-is will not help. Send it rephrased as one factual statement; \nnothing was charged.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Water boils at 100 C at sea level.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"hello there\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\"\n },\n {\n \"claim\": \"vendor is down\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"upstream_unavailable\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"A model provider was unavailable for this item. Retry it; nothing was charged.\"\n },\n {\n \"claim\": \"cannot frame\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"framing_failed\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"This item could not be processed; retrying it as-is will not help. Send it rephrased as one factual statement; nothing was charged.\"\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Water boils at 100 C at sea level.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"hello there\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.\"\n },\n {\n \"claim\": \"vendor is down\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"upstream_unavailable\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"A model provider was unavailable for this item. Retry it; nothing was charged.\"\n },\n {\n \"claim\": \"cannot frame\",\n \"language\": \"en\",\n \"verdict\": \"Error\",\n \"confidence\": \"low\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": \"framing_failed\",\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": \"This item could not be processed; retrying it as-is will not help. Send it rephrased as one factual statement; nothing was charged.\"\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='Water boils at 100 C at sea level.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='hello there', language='en', verdict='Error', confidence='low', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code='no_claim', candidate_claims=[], identified_claims=[], hint='The input is a greeting. Send one factual claim, or run the text through /extract to enumerate its claims.'), AssessClaim(claim='vendor is down', language='en', verdict='Error', confidence='low', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code='upstream_unavailable', candidate_claims=[], identified_claims=[], hint='A model provider was unavailable for this item. Retry it; nothing was charged.'), AssessClaim(claim='cannot frame', language='en', verdict='Error', confidence='low', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code='framing_failed', candidate_claims=[], identified_claims=[], hint='This item could not be processed; retrying it as-is will not help. Send it rephrased as one factual statement; nothing was charged.')], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__memo_hit.json b/tests/fixtures/parity/expected/assess__memo_hit.json index df5db6d..9fad459 100644 --- a/tests/fixtures/parity/expected/assess__memo_hit.json +++ b/tests/fixtures/parity/expected/assess__memo_hit.json @@ -21,6 +21,27 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "The Danube flows through Vienna.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": "The river runs through the city.", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "more_claims": [] + }, "render": "True (high) — The Danube flows through Vienna.\n The river runs through the city.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Danube flows through Vienna.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"The river runs through the city.\",\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Danube flows through Vienna.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"The river runs through the city.\",\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='The Danube flows through Vienna.', language='en', verdict='True', confidence='high', verification_url=None, rationale='The river runs through the city.', dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None)], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__replay_later_200.json b/tests/fixtures/parity/expected/assess__replay_later_200.json index cb3d6d5..614661f 100644 --- a/tests/fixtures/parity/expected/assess__replay_later_200.json +++ b/tests/fixtures/parity/expected/assess__replay_later_200.json @@ -21,6 +21,27 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "The Earth orbits the Sun.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "more_claims": [] + }, "render": "True (high) — The Earth orbits the Sun.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Earth orbits the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The Earth orbits the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='The Earth orbits the Sun.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None)], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__single_no_claim.json b/tests/fixtures/parity/expected/assess__single_no_claim.json index 2c5225e..71489d8 100644 --- a/tests/fixtures/parity/expected/assess__single_no_claim.json +++ b/tests/fixtures/parity/expected/assess__single_no_claim.json @@ -6,6 +6,14 @@ "error_code": "no_claim", "more_claims": [] }, + "dump_unset": { + "candidate_claims": [], + "claims": [], + "error": "No verifiable claim detected", + "error_code": "no_claim", + "more_claims": [] + }, "render": "No claim found.\n", - "render_json": "{\n \"claims\": [],\n \"error\": \"No verifiable claim detected\",\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [],\n \"error\": \"No verifiable claim detected\",\n \"error_code\": \"no_claim\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[], error='No verifiable claim detected', error_code='no_claim', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__single_one_claim.json b/tests/fixtures/parity/expected/assess__single_one_claim.json index 6a00522..a5ad7b9 100644 --- a/tests/fixtures/parity/expected/assess__single_one_claim.json +++ b/tests/fixtures/parity/expected/assess__single_one_claim.json @@ -21,6 +21,27 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "The registry reported 4,200 filings in 2024.", + "confidence": "high", + "dissent": "The registry figure is provisional, so the 2024 total cannot yet be confirmed.", + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": "The registry lists 4,200 filings for 2024 and has not revised the figure.", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "more_claims": [] + }, "render": "True (high) — The registry reported 4,200 filings in 2024.\n The registry lists 4,200 filings for 2024 and has not revised the figure.\n One reviewer disagreed: The registry figure is provisional, so the 2024 total cannot yet be confirmed.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The registry reported 4,200 filings in 2024.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"The registry lists 4,200 filings for 2024 and has not revised the figure.\",\n \"dissent\": \"The registry figure is provisional, so the 2024 total cannot yet be confirmed.\",\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"The registry reported 4,200 filings in 2024.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"The registry lists 4,200 filings for 2024 and has not revised the figure.\",\n \"dissent\": \"The registry figure is provisional, so the 2024 total cannot yet be confirmed.\",\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='The registry reported 4,200 filings in 2024.', language='en', verdict='True', confidence='high', verification_url=None, rationale='The registry lists 4,200 filings for 2024 and has not revised the figure.', dissent='The registry figure is provisional, so the 2024 total cannot yet be confirmed.', suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None)], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__single_text_over_wave_more_claims.json b/tests/fixtures/parity/expected/assess__single_text_over_wave_more_claims.json index 519a6b2..1a19a79 100644 --- a/tests/fixtures/parity/expected/assess__single_text_over_wave_more_claims.json +++ b/tests/fixtures/parity/expected/assess__single_text_over_wave_more_claims.json @@ -290,6 +290,296 @@ "Claim number 21 is documented." ] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "Claim number 0 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 1 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 2 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 3 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 4 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 5 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 6 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 7 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 8 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 9 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 10 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 11 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 12 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 13 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 14 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 15 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 16 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 17 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 18 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Claim number 19 is documented.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "more_claims": [ + "Claim number 20 is documented.", + "Claim number 21 is documented." + ] + }, "render": "True (high) — Claim number 0 is documented.\nTrue (high) — Claim number 1 is documented.\nTrue (high) — Claim number 2 is documented.\nTrue (high) — Claim number 3 is documented.\nTrue (high) — Claim number 4 is documented.\nTrue (high) — Claim number 5 is documented.\nTrue (high) — Claim number 6 is documented.\nTrue (high) — Claim number 7 is documented.\nTrue (high) — Claim number 8 is documented.\nTrue (high) — Claim number 9 is documented.\nTrue (high) — Claim number 10 is documented.\nTrue (high) — Claim number 11 is documented.\nTrue (high) — Claim number 12 is documented.\nTrue (high) — Claim number 13 is documented.\nTrue (high) — Claim number 14 is documented.\nTrue (high) — Claim number 15 is documented.\nTrue (high) — Claim number 16 is documented.\nTrue (high) — Claim number 17 is documented.\nTrue (high) — Claim number 18 is documented.\nTrue (high) — Claim number 19 is documented.\n\nNot checked (2 more claims found; pass them to `lenz assess`, 20 a call):\n • Claim number 20 is documented.\n • Claim number 21 is documented.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Claim number 0 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 1 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 2 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 3 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 4 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 5 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 6 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 7 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 8 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 9 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 10 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 11 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 12 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 13 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 14 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 15 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 16 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 17 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 18 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 19 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": [\n \"Claim number 20 is documented.\",\n \"Claim number 21 is documented.\"\n ]\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Claim number 0 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 1 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 2 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 3 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 4 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 5 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 6 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 7 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 8 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 9 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 10 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 11 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 12 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 13 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 14 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 15 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 16 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 17 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 18 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Claim number 19 is documented.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": [\n \"Claim number 20 is documented.\",\n \"Claim number 21 is documented.\"\n ]\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='Claim number 0 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 1 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 2 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 3 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 4 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 5 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 6 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 7 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 8 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 9 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 10 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 11 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 12 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 13 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 14 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 15 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 16 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 17 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 18 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Claim number 19 is documented.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None)], error=None, error_code='', candidate_claims=[], more_claims=['Claim number 20 is documented.', 'Claim number 21 is documented.'])" } diff --git a/tests/fixtures/parity/expected/assess__single_text_several_claims.json b/tests/fixtures/parity/expected/assess__single_text_several_claims.json index 62e14ad..c3d142e 100644 --- a/tests/fixtures/parity/expected/assess__single_text_several_claims.json +++ b/tests/fixtures/parity/expected/assess__single_text_several_claims.json @@ -49,6 +49,55 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "Water boils at 100 C at sea level.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "The Moon is made of cheese.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "The Pacific is the deepest ocean.", + "confidence": "medium", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": null, + "suggested_rewrite": null, + "verdict": "Mostly True", + "verification_url": null + } + ], + "error": null, + "more_claims": [] + }, "render": "True (high) — Water boils at 100 C at sea level.\nFalse (high) — The Moon is made of cheese.\nMostly True (medium) — The Pacific is the deepest ocean.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Water boils at 100 C at sea level.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"The Moon is made of cheese.\",\n \"language\": \"en\",\n \"verdict\": \"False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"The Pacific is the deepest ocean.\",\n \"language\": \"en\",\n \"verdict\": \"Mostly True\",\n \"confidence\": \"medium\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Water boils at 100 C at sea level.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"The Moon is made of cheese.\",\n \"language\": \"en\",\n \"verdict\": \"False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"The Pacific is the deepest ocean.\",\n \"language\": \"en\",\n \"verdict\": \"Mostly True\",\n \"confidence\": \"medium\",\n \"verification_url\": null,\n \"rationale\": null,\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='Water boils at 100 C at sea level.', language='en', verdict='True', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='The Moon is made of cheese.', language='en', verdict='False', confidence='high', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='The Pacific is the deepest ocean.', language='en', verdict='Mostly True', confidence='medium', verification_url=None, rationale=None, dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None)], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/assess__suggest_rewrite.json b/tests/fixtures/parity/expected/assess__suggest_rewrite.json index da850bb..e24cfab 100644 --- a/tests/fixtures/parity/expected/assess__suggest_rewrite.json +++ b/tests/fixtures/parity/expected/assess__suggest_rewrite.json @@ -35,6 +35,41 @@ "error_code": "", "more_claims": [] }, + "dump_unset": { + "claims": [ + { + "candidate_claims": [], + "claim": "Venus is the closest planet to the Sun.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": "Mercury, not Venus, is the closest planet to the Sun.", + "suggested_rewrite": "Mercury is the closest planet to the Sun.", + "verdict": "False", + "verification_url": null + }, + { + "candidate_claims": [], + "claim": "Mercury is the closest planet to the Sun.", + "confidence": "high", + "dissent": null, + "error_code": null, + "hint": null, + "identified_claims": [], + "language": "en", + "rationale": "Mercury is the innermost planet.", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + } + ], + "error": null, + "more_claims": [] + }, "render": "False (high) — Venus is the closest planet to the Sun.\n Mercury, not Venus, is the closest planet to the Sun.\nTrue (high) — Mercury is the closest planet to the Sun.\n Mercury is the innermost planet.\n", - "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Venus is the closest planet to the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"Mercury, not Venus, is the closest planet to the Sun.\",\n \"dissent\": null,\n \"suggested_rewrite\": \"Mercury is the closest planet to the Sun.\",\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Mercury is the closest planet to the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"Mercury is the innermost planet.\",\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n" + "render_json": "{\n \"claims\": [\n {\n \"claim\": \"Venus is the closest planet to the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"False\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"Mercury, not Venus, is the closest planet to the Sun.\",\n \"dissent\": null,\n \"suggested_rewrite\": \"Mercury is the closest planet to the Sun.\",\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n },\n {\n \"claim\": \"Mercury is the closest planet to the Sun.\",\n \"language\": \"en\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"verification_url\": null,\n \"rationale\": \"Mercury is the innermost planet.\",\n \"dissent\": null,\n \"suggested_rewrite\": null,\n \"error_code\": null,\n \"candidate_claims\": [],\n \"identified_claims\": [],\n \"hint\": null\n }\n ],\n \"error\": null,\n \"error_code\": \"\",\n \"candidate_claims\": [],\n \"more_claims\": []\n}\n", + "repr": "AssessResponse(claims=[AssessClaim(claim='Venus is the closest planet to the Sun.', language='en', verdict='False', confidence='high', verification_url=None, rationale='Mercury, not Venus, is the closest planet to the Sun.', dissent=None, suggested_rewrite='Mercury is the closest planet to the Sun.', error_code=None, candidate_claims=[], identified_claims=[], hint=None), AssessClaim(claim='Mercury is the closest planet to the Sun.', language='en', verdict='True', confidence='high', verification_url=None, rationale='Mercury is the innermost planet.', dissent=None, suggested_rewrite=None, error_code=None, candidate_claims=[], identified_claims=[], hint=None)], error=None, error_code='', candidate_claims=[], more_claims=[])" } diff --git a/tests/fixtures/parity/expected/citecheck__402_no_credits.json b/tests/fixtures/parity/expected/citecheck__402_no_credits.json index 9d5ec22..add7b94 100644 --- a/tests/fixtures/parity/expected/citecheck__402_no_credits.json +++ b/tests/fixtures/parity/expected/citecheck__402_no_credits.json @@ -20,7 +20,7 @@ "remaining": 100, "request_id": "", "requested": null, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "status_code": 402, "type": "LenzQuotaExceededError", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" diff --git a/tests/fixtures/parity/expected/citecheck__422_webhook_secret_missing.json b/tests/fixtures/parity/expected/citecheck__422_webhook_secret_missing.json new file mode 100644 index 0000000..aa5a20c --- /dev/null +++ b/tests/fixtures/parity/expected/citecheck__422_webhook_secret_missing.json @@ -0,0 +1,30 @@ +{ + "error": { + "cause": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "code": "webhook_secret_missing", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "webhook_url" + ], + "msg": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.\n Fix: Check the request body against the OpenAPI spec.", + "message": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/citecheck__get_checking.json b/tests/fixtures/parity/expected/citecheck__get_checking.json index c5352dd..2490a65 100644 --- a/tests/fixtures/parity/expected/citecheck__get_checking.json +++ b/tests/fixtures/parity/expected/citecheck__get_checking.json @@ -68,7 +68,102 @@ ], "citecheck_id": "8eb49302", "completed_at": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": null, + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": 10, + "status": "checking", + "summary": { + "citation_checks": { + "checked": 0, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "pending", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": null, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "pending", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": null, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": null, + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -96,5 +191,6 @@ }, "exit_code": 2, "render": "Citation check 8eb49302: checking — 0 credits charged\n\n2 sources cited in your draft\nLenz checks each one: does the source say what your draft says it does.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='checking', outcome=None, created_at='2026-10-01T09:07:00.123456Z', completed_at=None, poll_after_seconds=10, policy=CitecheckPolicy(max_citations=2), summary=CitecheckSummary(citations_found=2, citations_selected=2, citation_limit=2, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=0, unchecked=0, failed=0), citation_issues=0), credits=ReviewCredits(charged=0), citations=[ReviewCitation(index=0, reference='https://example.gov/report-2024', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024.', quotes=[], position=None, result=None, check=ReviewCitationCheck(status='pending', page_read=None, page_title=None, page_published_date=None, page_language=None, source_url=None, source_version=None, support=None, snippet=None, rationale=None, quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='https://example.org/statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=None, result=None, check=ReviewCitationCheck(status='pending', page_read=None, page_title=None, page_published_date=None, page_language=None, source_url=None, source_version=None, support=None, snippet=None, rationale=None, quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))], citation_issues=[], citation_failures=[], more_citations=[], failure=None, language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_clean.json b/tests/fixtures/parity/expected/citecheck__get_completed_clean.json index 0b78c9e..e1cfe30 100644 --- a/tests/fixtures/parity/expected/citecheck__get_completed_clean.json +++ b/tests/fixtures/parity/expected/citecheck__get_completed_clean.json @@ -75,8 +75,111 @@ } ], "citecheck_id": "8eb49302", - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "clean", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -104,5 +207,6 @@ }, "exit_code": 0, "render": "Citation check 8eb49302: clean — 2 credits charged\n\n2 sources cited in your draft\n2 checked.\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', poll_after_seconds=None, policy=CitecheckPolicy(max_citations=2), summary=CitecheckSummary(citations_found=2, citations_selected=2, citation_limit=2, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=0), credits=ReviewCredits(charged=2), citations=[ReviewCitation(index=0, reference='https://example.gov/report-2024', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024.', quotes=[], position=None, result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='https://example.org/statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=None, result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))], citation_issues=[], citation_failures=[], more_citations=[], failure=None, language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_doi_pair.json b/tests/fixtures/parity/expected/citecheck__get_completed_doi_pair.json index 1857179..e793493 100644 --- a/tests/fixtures/parity/expected/citecheck__get_completed_doi_pair.json +++ b/tests/fixtures/parity/expected/citecheck__get_completed_doi_pair.json @@ -40,8 +40,76 @@ } ], "citecheck_id": "8eb49302", - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "clean", + "policy": { + "max_citations": 1 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 1, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 1, + "citation_limit_reached": false, + "citations_found": 1, + "citations_selected": 1 + } + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at None", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": null, + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://doi.org/10.1038/nature12373", + "doi": "10.1038/nature12373", + "index": 0, + "position": null, + "quotes": [], + "reference": "10.1038/nature12373", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Diamond sensors measure heat in cells." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -69,5 +137,6 @@ }, "exit_code": 0, "render": "Citation check 8eb49302: clean — 1 credit charged\n\n1 source cited in your draft\n1 checked.\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', poll_after_seconds=None, policy=CitecheckPolicy(max_citations=1), summary=CitecheckSummary(citations_found=1, citations_selected=1, citation_limit=1, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=1, unchecked=0, failed=0), citation_issues=0), credits=ReviewCredits(charged=1), citations=[ReviewCitation(index=0, reference='10.1038/nature12373', cited_url='https://doi.org/10.1038/nature12373', doi='10.1038/nature12373', statement='Diamond sensors measure heat in cells.', quotes=[], position=None, result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at None', page_published_date=None, page_language='en', source_url=None, source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))], citation_issues=[], citation_failures=[], more_citations=[], failure=None, language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_incomplete.json b/tests/fixtures/parity/expected/citecheck__get_completed_incomplete.json index 267612f..9a2c57c 100644 --- a/tests/fixtures/parity/expected/citecheck__get_completed_incomplete.json +++ b/tests/fixtures/parity/expected/citecheck__get_completed_incomplete.json @@ -91,8 +91,127 @@ } ], "citecheck_id": "8eb49302", - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "incomplete", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 1, + "failed": 1, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "dump_unset": { + "citation_failures": [ + { + "citation_index": 1, + "cited_url": "https://example.org/statement", + "doi": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#internal", + "failure_class": "internal", + "failure_reason": "internal", + "hint": "The check failed on our side. Try again later.", + "retryable": false + }, + "reference": "https://example.org/statement" + } + ], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#internal", + "failure_class": "internal", + "failure_reason": "internal", + "hint": "The check failed on our side. Try again later.", + "retryable": false + }, + "hint": "The check failed on our side. Try again later.", + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "failed", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": null, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -120,5 +239,6 @@ }, "exit_code": 2, "render": "Citation check 8eb49302: incomplete — 1 credit charged\n\n2 sources cited in your draft\n1 checked. 1 could not be checked.\n\n[source 2/2] Could not be checked this time.\n https://example.org/statement\n The check failed on our side. Try again later.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='completed', outcome='incomplete', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', poll_after_seconds=None, policy=CitecheckPolicy(max_citations=2), summary=CitecheckSummary(citations_found=2, citations_selected=2, citation_limit=2, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=1, unchecked=0, failed=1), citation_issues=0), credits=ReviewCredits(charged=1), citations=[ReviewCitation(index=0, reference='https://example.gov/report-2024', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024.', quotes=[], position=None, result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='https://example.org/statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=None, result=None, check=ReviewCitationCheck(status='failed', page_read=None, page_title=None, page_published_date=None, page_language=None, source_url=None, source_version=None, support=None, snippet=None, rationale=None, quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint='The check failed on our side. Try again later.', failure=FailureBlock(failure_reason='internal', failure_class='internal', retryable=False, hint='The check failed on our side. Try again later.', docs_url='https://lenz.io/docs/errors#internal')))], citation_issues=[], citation_failures=[ReviewCitationFailure(citation_index=1, reference='https://example.org/statement', cited_url='https://example.org/statement', doi=None, failure=FailureBlock(failure_reason='internal', failure_class='internal', retryable=False, hint='The check failed on our side. Try again later.', docs_url='https://lenz.io/docs/errors#internal'))], more_citations=[], failure=None, language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_issues_found.json b/tests/fixtures/parity/expected/citecheck__get_completed_issues_found.json index 0bee066..2d22ac8 100644 --- a/tests/fixtures/parity/expected/citecheck__get_completed_issues_found.json +++ b/tests/fixtures/parity/expected/citecheck__get_completed_issues_found.json @@ -105,8 +105,141 @@ } ], "citecheck_id": "8eb49302", - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "issues_found", + "policy": { + "max_citations": 20 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 1, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": null, + "finding": "contradicted", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "rationale": "The page states it.", + "reference": "a report from the ministry", + "snippet": "The source says so.", + "source": "support", + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + } + ], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "contradicted", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "contradicted", + "is_issue": true, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -134,5 +267,6 @@ }, "exit_code": 1, "render": "Citation check 8eb49302: issues found — 2 credits charged\n\n2 sources cited in your draft\n2 checked, 1 with a problem.\n\n[source 1/2] Contradicted\n Unemployment fell to 4.1% in 2024, according to a report from the ministry.\n https://example.gov/report-2024\n The source says:\n “The source says so.”\n Reviewer's note: The page states it.\n\nA reviewer's note is reasoning, not a checked source; the quoted passage is from the page.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='completed', outcome='issues_found', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', poll_after_seconds=None, policy=CitecheckPolicy(max_citations=20), summary=CitecheckSummary(citations_found=2, citations_selected=2, citation_limit=20, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=1), credits=ReviewCredits(charged=2), citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=ReviewCitationResult(finding='contradicted', source='support', is_issue=True), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='contradicted', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=Position(start=111, end=178, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))], citation_issues=[ReviewCitationIssue(citation_index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), finding='contradicted', source='support', snippet='The source says so.', rationale='The page states it.', missing_quote=None, metadata_differences=[], page_title='Page at https://example.gov/report-2024', failure=None)], citation_failures=[], more_citations=[], failure=None, language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_partly_supported.json b/tests/fixtures/parity/expected/citecheck__get_completed_partly_supported.json index 3d302ef..8077d22 100644 --- a/tests/fixtures/parity/expected/citecheck__get_completed_partly_supported.json +++ b/tests/fixtures/parity/expected/citecheck__get_completed_partly_supported.json @@ -75,8 +75,111 @@ } ], "citecheck_id": "8eb49302", - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "clean", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "partly_supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": { + "finding": "partly_supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -104,5 +207,6 @@ }, "exit_code": 0, "render": "Citation check 8eb49302: clean — 2 credits charged\n\n2 sources cited in your draft\n2 checked.\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', poll_after_seconds=None, policy=CitecheckPolicy(max_citations=2), summary=CitecheckSummary(citations_found=2, citations_selected=2, citation_limit=2, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=0), credits=ReviewCredits(charged=2), citations=[ReviewCitation(index=0, reference='https://example.gov/report-2024', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024.', quotes=[], position=None, result=ReviewCitationResult(finding='partly_supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='partly_supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='https://example.org/statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=None, result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))], citation_issues=[], citation_failures=[], more_citations=[], failure=None, language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_completed_unchecked.json b/tests/fixtures/parity/expected/citecheck__get_completed_unchecked.json index 4e9a931..b5c061f 100644 --- a/tests/fixtures/parity/expected/citecheck__get_completed_unchecked.json +++ b/tests/fixtures/parity/expected/citecheck__get_completed_unchecked.json @@ -75,8 +75,111 @@ } ], "citecheck_id": "8eb49302", - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "unchecked", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 0, + "failed": 0, + "unchecked": 2 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": null, + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "unchecked", + "unchecked_reason": "no_text" + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": { + "finding": "unchecked", + "is_issue": false, + "source": null + }, + "statement": "Unemployment fell to 4.1% in 2024." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": null, + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "unchecked", + "unchecked_reason": "no_text" + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "https://example.org/statement", + "result": { + "finding": "unchecked", + "is_issue": false, + "source": null + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -104,5 +207,6 @@ }, "exit_code": 2, "render": "Citation check 8eb49302: unchecked — 0 credits charged\n\n2 sources cited in your draft\n2 could not be checked.\n\nCheck these by hand (Lenz could not check them)\n[source 1/2] The page gave no text to read.\n https://example.gov/report-2024\n[source 2/2] The page gave no text to read.\n https://example.org/statement\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='completed', outcome='unchecked', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', poll_after_seconds=None, policy=CitecheckPolicy(max_citations=2), summary=CitecheckSummary(citations_found=2, citations_selected=2, citation_limit=2, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=0, unchecked=2, failed=0), citation_issues=0), credits=ReviewCredits(charged=0), citations=[ReviewCitation(index=0, reference='https://example.gov/report-2024', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024.', quotes=[], position=None, result=ReviewCitationResult(finding='unchecked', source=None, is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='unchecked', snippet=None, rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason='no_text', hint=None, failure=None)), ReviewCitation(index=1, reference='https://example.org/statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=None, result=ReviewCitationResult(finding='unchecked', source=None, is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='unchecked', snippet=None, rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason='no_text', hint=None, failure=None))], citation_issues=[], citation_failures=[], more_citations=[], failure=None, language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_failed_no_citations.json b/tests/fixtures/parity/expected/citecheck__get_failed_no_citations.json index 2fcc755..fbc25bf 100644 --- a/tests/fixtures/parity/expected/citecheck__get_failed_no_citations.json +++ b/tests/fixtures/parity/expected/citecheck__get_failed_no_citations.json @@ -4,8 +4,42 @@ "citation_issues": [], "citations": [], "citecheck_id": "8eb49302", - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "no_citations", + "hint": "The text has no citation to check: no link, DOI or numbered reference with one.", + "retryable": false + }, + "language": "en", + "more_citations": null, + "outcome": "unchecked", + "policy": { + "max_citations": 20 + }, + "poll_after_seconds": null, + "status": "failed", + "summary": { + "citation_checks": null, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null + } + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -35,5 +69,6 @@ }, "exit_code": 2, "render": "Citation check 8eb49302: unchecked — 0 credits charged\nFailed: The text has no citation to check: no link, DOI or numbered reference with one.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='failed', outcome='unchecked', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', poll_after_seconds=None, policy=CitecheckPolicy(max_citations=20), summary=CitecheckSummary(citations_found=None, citations_selected=None, citation_limit=20, citation_limit_reached=None, citation_checks=None, citation_issues=0), credits=ReviewCredits(charged=0), citations=[], citation_issues=[], citation_failures=[], more_citations=None, failure=FailureBlock(failure_reason='no_citations', failure_class='invalid_input', retryable=False, hint='The text has no citation to check: no link, DOI or numbered reference with one.', docs_url='https://lenz.io/docs/errors#invalid-input'), language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_failed_upstream_unavailable.json b/tests/fixtures/parity/expected/citecheck__get_failed_upstream_unavailable.json index 81d92d8..8365eb9 100644 --- a/tests/fixtures/parity/expected/citecheck__get_failed_upstream_unavailable.json +++ b/tests/fixtures/parity/expected/citecheck__get_failed_upstream_unavailable.json @@ -106,8 +106,148 @@ } ], "citecheck_id": "8eb49302", - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": null, + "retryable": true + }, + "language": "en", + "more_citations": [], + "outcome": "unchecked", + "policy": { + "max_citations": 20 + }, + "poll_after_seconds": null, + "status": "failed", + "summary": { + "citation_checks": { + "checked": 0, + "failed": 2, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "dump_unset": { + "citation_failures": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "Lenz could not reach this source just now. Try again later.", + "retryable": true + }, + "reference": "a report from the ministry" + }, + { + "citation_index": 1, + "cited_url": "https://example.org/statement", + "doi": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "Lenz could not reach this source just now. Try again later.", + "retryable": true + }, + "reference": "a statement" + } + ], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "Lenz could not reach this source just now. Try again later.", + "retryable": true + }, + "hint": "Lenz could not reach this source just now. Try again later.", + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "failed", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "a report from the ministry", + "result": null, + "statement": null + }, + { + "check": { + "doi_registered": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "Lenz could not reach this source just now. Try again later.", + "retryable": true + }, + "hint": "Lenz could not reach this source just now. Try again later.", + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "failed", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "a statement", + "result": null, + "statement": null + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -141,5 +281,6 @@ }, "exit_code": 2, "render": "Citation check 8eb49302: unchecked — 0 credits charged\nFailed: upstream_unavailable\n\n2 sources cited in your draft\n2 could not be checked.\n\n[source 1/2] Could not be checked this time.\n https://example.gov/report-2024\n Lenz could not reach this source just now. Try again later.\n\n[source 2/2] Could not be checked this time.\n https://example.org/statement\n Lenz could not reach this source just now. Try again later.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='failed', outcome='unchecked', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', poll_after_seconds=None, policy=CitecheckPolicy(max_citations=20), summary=CitecheckSummary(citations_found=2, citations_selected=2, citation_limit=20, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=0, unchecked=0, failed=2), citation_issues=0), credits=ReviewCredits(charged=0), citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement=None, quotes=[], position=None, result=None, check=ReviewCitationCheck(status='failed', page_read=None, page_title=None, page_published_date=None, page_language=None, source_url=None, source_version=None, support=None, snippet=None, rationale=None, quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint='Lenz could not reach this source just now. Try again later.', failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='Lenz could not reach this source just now. Try again later.', docs_url='https://lenz.io/docs/errors#upstream-unavailable'))), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement=None, quotes=[], position=None, result=None, check=ReviewCitationCheck(status='failed', page_read=None, page_title=None, page_published_date=None, page_language=None, source_url=None, source_version=None, support=None, snippet=None, rationale=None, quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint='Lenz could not reach this source just now. Try again later.', failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='Lenz could not reach this source just now. Try again later.', docs_url='https://lenz.io/docs/errors#upstream-unavailable')))], citation_issues=[], citation_failures=[ReviewCitationFailure(citation_index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='Lenz could not reach this source just now. Try again later.', docs_url='https://lenz.io/docs/errors#upstream-unavailable')), ReviewCitationFailure(citation_index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='Lenz could not reach this source just now. Try again later.', docs_url='https://lenz.io/docs/errors#upstream-unavailable'))], more_citations=[], failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint=None, docs_url='https://lenz.io/docs/errors#upstream-unavailable'), language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_queued.json b/tests/fixtures/parity/expected/citecheck__get_queued.json index 402fbe9..b74baa6 100644 --- a/tests/fixtures/parity/expected/citecheck__get_queued.json +++ b/tests/fixtures/parity/expected/citecheck__get_queued.json @@ -37,7 +37,71 @@ ], "citecheck_id": "8eb49302", "completed_at": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": null, + "policy": { + "max_citations": 1 + }, + "poll_after_seconds": 10, + "status": "queued", + "summary": { + "citation_checks": { + "checked": 0, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 1, + "citation_limit_reached": false, + "citations_found": 1, + "citations_selected": 1 + } + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "pending", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "https://example.gov/report-2024", + "result": null, + "statement": "Unemployment fell to 4.1% in 2024." + } + ], + "citecheck_id": "8eb49302", + "completed_at": null, + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -65,5 +129,6 @@ }, "exit_code": 2, "render": "Citation check 8eb49302: queued — 0 credits charged\n\n1 source cited in your draft\nLenz checks each one: does the source say what your draft says it does.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='queued', outcome=None, created_at='2026-10-01T09:07:00.123456Z', completed_at=None, poll_after_seconds=10, policy=CitecheckPolicy(max_citations=1), summary=CitecheckSummary(citations_found=1, citations_selected=1, citation_limit=1, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=0, unchecked=0, failed=0), citation_issues=0), credits=ReviewCredits(charged=0), citations=[ReviewCitation(index=0, reference='https://example.gov/report-2024', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024.', quotes=[], position=None, result=None, check=ReviewCitationCheck(status='pending', page_read=None, page_title=None, page_published_date=None, page_language=None, source_url=None, source_version=None, support=None, snippet=None, rationale=None, quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))], citation_issues=[], citation_failures=[], more_citations=[], failure=None, language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_text_limit_exactly_at_limit.json b/tests/fixtures/parity/expected/citecheck__get_text_limit_exactly_at_limit.json index 174ac25..f3818cf 100644 --- a/tests/fixtures/parity/expected/citecheck__get_text_limit_exactly_at_limit.json +++ b/tests/fixtures/parity/expected/citecheck__get_text_limit_exactly_at_limit.json @@ -83,8 +83,119 @@ } ], "citecheck_id": "8eb49302", - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "language": "en", + "more_citations": [], + "outcome": "clean", + "policy": { + "max_citations": 2 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2 + } + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -112,5 +223,6 @@ }, "exit_code": 0, "render": "Citation check 8eb49302: clean — 2 credits charged\n\n2 sources cited in your draft\n2 checked.\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', poll_after_seconds=None, policy=CitecheckPolicy(max_citations=2), summary=CitecheckSummary(citations_found=2, citations_selected=2, citation_limit=2, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=0), credits=ReviewCredits(charged=2), citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=Position(start=111, end=178, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))], citation_issues=[], citation_failures=[], more_citations=[], failure=None, language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__get_text_limit_reached.json b/tests/fixtures/parity/expected/citecheck__get_text_limit_reached.json index b97967a..bd075a8 100644 --- a/tests/fixtures/parity/expected/citecheck__get_text_limit_reached.json +++ b/tests/fixtures/parity/expected/citecheck__get_text_limit_reached.json @@ -44,8 +44,93 @@ } ], "citecheck_id": "8eb49302", - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "language": "en", + "more_citations": [ + { + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "reference": "a statement", + "sentence": "The agency said so in a statement." + } + ], + "outcome": "clean", + "policy": { + "max_citations": 1 + }, + "poll_after_seconds": null, + "status": "completed", + "summary": { + "citation_checks": { + "checked": 1, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 1, + "citation_limit_reached": true, + "citations_found": 2, + "citations_selected": 1 + } + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + } + ], + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -86,5 +171,6 @@ }, "exit_code": 0, "render": "Citation check 8eb49302: clean — 1 credit charged\n\n2 sources cited in your draft\n1 checked.\n1 more was not checked: one check covers 1.\n\nNo issues.\n\n1 more citation was found but not checked.\n", - "render_json": null + "render_json": null, + "repr": "Citecheck(citecheck_id='8eb49302', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', poll_after_seconds=None, policy=CitecheckPolicy(max_citations=1), summary=CitecheckSummary(citations_found=2, citations_selected=1, citation_limit=1, citation_limit_reached=True, citation_checks=ReviewCitationCheckCounts(checked=1, unchecked=0, failed=0), citation_issues=0), credits=ReviewCredits(charged=1), citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))], citation_issues=[], citation_failures=[], more_citations=[ReviewMoreCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, sentence='The agency said so in a statement.', position=Position(start=111, end=178, text=None))], failure=None, language='en')" } diff --git a/tests/fixtures/parity/expected/citecheck__idempotent_replay_202.json b/tests/fixtures/parity/expected/citecheck__idempotent_replay_202.json index 6ebcb9b..a0700ca 100644 --- a/tests/fixtures/parity/expected/citecheck__idempotent_replay_202.json +++ b/tests/fixtures/parity/expected/citecheck__idempotent_replay_202.json @@ -3,5 +3,10 @@ "citecheck_id": "8eb49302", "status": "queued" }, - "render_json": null + "dump_unset": { + "citecheck_id": "8eb49302", + "status": "queued" + }, + "render_json": null, + "repr": "CitecheckStarted(citecheck_id='8eb49302', status='queued')" } diff --git a/tests/fixtures/parity/expected/citecheck__receipt_202.json b/tests/fixtures/parity/expected/citecheck__receipt_202.json index 6ebcb9b..a0700ca 100644 --- a/tests/fixtures/parity/expected/citecheck__receipt_202.json +++ b/tests/fixtures/parity/expected/citecheck__receipt_202.json @@ -3,5 +3,10 @@ "citecheck_id": "8eb49302", "status": "queued" }, - "render_json": null + "dump_unset": { + "citecheck_id": "8eb49302", + "status": "queued" + }, + "render_json": null, + "repr": "CitecheckStarted(citecheck_id='8eb49302', status='queued')" } diff --git a/tests/fixtures/parity/expected/citecheck__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/expected/citecheck__receipt_202_empty_webhook_url.json index 6ebcb9b..a0700ca 100644 --- a/tests/fixtures/parity/expected/citecheck__receipt_202_empty_webhook_url.json +++ b/tests/fixtures/parity/expected/citecheck__receipt_202_empty_webhook_url.json @@ -3,5 +3,10 @@ "citecheck_id": "8eb49302", "status": "queued" }, - "render_json": null + "dump_unset": { + "citecheck_id": "8eb49302", + "status": "queued" + }, + "render_json": null, + "repr": "CitecheckStarted(citecheck_id='8eb49302', status='queued')" } diff --git a/tests/fixtures/parity/expected/errors__auth_bad_oauth_token.json b/tests/fixtures/parity/expected/errors__auth_bad_oauth_token.json new file mode 100644 index 0000000..5186317 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_bad_oauth_token.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "The access token is invalid, expired or revoked.", + "code": "invalid_token", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "The access token is invalid, expired or revoked.\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "The access token is invalid, expired or revoked.", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "The access token is invalid, expired or revoked.", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_expired_oauth_token.json b/tests/fixtures/parity/expected/errors__auth_expired_oauth_token.json new file mode 100644 index 0000000..5186317 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_expired_oauth_token.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "The access token is invalid, expired or revoked.", + "code": "invalid_token", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "The access token is invalid, expired or revoked.\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "The access token is invalid, expired or revoked.", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "The access token is invalid, expired or revoked.", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_oauth_issuer_off.json b/tests/fixtures/parity/expected/errors__auth_oauth_issuer_off.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_oauth_issuer_off.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__auth_oauth_only.json b/tests/fixtures/parity/expected/errors__auth_oauth_only.json new file mode 100644 index 0000000..99f0634 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__auth_oauth_only.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.", + "code": "oauth_only", + "doc_url": "https://lenz.io/docs/auth", + "fix": "This key doesn't have access to that resource.", + "friendly_text": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.\n Fix: This key doesn't have access to that resource.", + "message": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "This key doesn't have access to that resource.", + "message": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.", + "status": 403 + } + }, + "request_id": "", + "status_code": 403, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__method_not_allowed_get_verify.json b/tests/fixtures/parity/expected/errors__method_not_allowed_get_verify.json new file mode 100644 index 0000000..ebe2cee --- /dev/null +++ b/tests/fixtures/parity/expected/errors__method_not_allowed_get_verify.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 405", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 405\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 405", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 405", + "status": 405 + } + }, + "request_id": "", + "status_code": 405, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__method_not_allowed_post_library.json b/tests/fixtures/parity/expected/errors__method_not_allowed_post_library.json new file mode 100644 index 0000000..ebe2cee --- /dev/null +++ b/tests/fixtures/parity/expected/errors__method_not_allowed_post_library.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 405", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 405\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 405", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 405", + "status": 405 + } + }, + "request_id": "", + "status_code": 405, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__oauth_register_disabled.json b/tests/fixtures/parity/expected/errors__oauth_register_disabled.json new file mode 100644 index 0000000..8c9406d --- /dev/null +++ b/tests/fixtures/parity/expected/errors__oauth_register_disabled.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 404", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 404\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 404", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 404", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__oauth_register_invalid_client_metadata.json b/tests/fixtures/parity/expected/errors__oauth_register_invalid_client_metadata.json new file mode 100644 index 0000000..3ae0fc8 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__oauth_register_invalid_client_metadata.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 400", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 400\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "status": 400 + } + }, + "request_id": "", + "status_code": 400, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__oauth_register_invalid_redirect_uri.json b/tests/fixtures/parity/expected/errors__oauth_register_invalid_redirect_uri.json new file mode 100644 index 0000000..3ae0fc8 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__oauth_register_invalid_redirect_uri.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 400", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 400\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "status": 400 + } + }, + "request_id": "", + "status_code": 400, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__oauth_revoke_invalid_client.json b/tests/fixtures/parity/expected/errors__oauth_revoke_invalid_client.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/errors__oauth_revoke_invalid_client.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__oauth_token_invalid_client.json b/tests/fixtures/parity/expected/errors__oauth_token_invalid_client.json new file mode 100644 index 0000000..e57982a --- /dev/null +++ b/tests/fixtures/parity/expected/errors__oauth_token_invalid_client.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Unauthorized", + "code": "", + "doc_url": "https://lenz.io/docs/auth", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "friendly_text": "Unauthorized\n Fix: Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "Your credential is missing, invalid or expired. Check the key you passed, or get a new one at https://lenz.io/api-credentials.", + "message": "Unauthorized", + "status": 401 + } + }, + "request_id": "", + "status_code": 401, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__oauth_token_invalid_grant.json b/tests/fixtures/parity/expected/errors__oauth_token_invalid_grant.json new file mode 100644 index 0000000..3ae0fc8 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__oauth_token_invalid_grant.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 400", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 400\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "status": 400 + } + }, + "request_id": "", + "status_code": 400, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__oauth_token_missing_grant_type.json b/tests/fixtures/parity/expected/errors__oauth_token_missing_grant_type.json new file mode 100644 index 0000000..3ae0fc8 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__oauth_token_missing_grant_type.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 400", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 400\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "status": 400 + } + }, + "request_id": "", + "status_code": 400, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__oauth_token_refresh_invalid_grant.json b/tests/fixtures/parity/expected/errors__oauth_token_refresh_invalid_grant.json new file mode 100644 index 0000000..3ae0fc8 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__oauth_token_refresh_invalid_grant.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 400", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 400\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "status": 400 + } + }, + "request_id": "", + "status_code": 400, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__oauth_token_unsupported_grant_type.json b/tests/fixtures/parity/expected/errors__oauth_token_unsupported_grant_type.json new file mode 100644 index 0000000..3ae0fc8 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__oauth_token_unsupported_grant_type.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 400", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 400\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 400", + "status": 400 + } + }, + "request_id": "", + "status_code": 400, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/errors__payment_required_ask.json b/tests/fixtures/parity/expected/errors__payment_required_ask.json index e519757..a635323 100644 --- a/tests/fixtures/parity/expected/errors__payment_required_ask.json +++ b/tests/fixtures/parity/expected/errors__payment_required_ask.json @@ -20,7 +20,7 @@ "remaining": 0, "request_id": "", "requested": null, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "status_code": 402, "type": "LenzQuotaExceededError", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" diff --git a/tests/fixtures/parity/expected/errors__payment_required_assess.json b/tests/fixtures/parity/expected/errors__payment_required_assess.json index 732bc39..91af7cd 100644 --- a/tests/fixtures/parity/expected/errors__payment_required_assess.json +++ b/tests/fixtures/parity/expected/errors__payment_required_assess.json @@ -20,7 +20,7 @@ "remaining": 0, "request_id": "", "requested": null, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "status_code": 402, "type": "LenzQuotaExceededError", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" diff --git a/tests/fixtures/parity/expected/errors__payment_required_verify.json b/tests/fixtures/parity/expected/errors__payment_required_verify.json index f3a12a3..f16364a 100644 --- a/tests/fixtures/parity/expected/errors__payment_required_verify.json +++ b/tests/fixtures/parity/expected/errors__payment_required_verify.json @@ -20,7 +20,7 @@ "remaining": 0, "request_id": "", "requested": null, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "status_code": 402, "type": "LenzQuotaExceededError", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" diff --git a/tests/fixtures/parity/expected/errors__payment_required_verify_batch_short.json b/tests/fixtures/parity/expected/errors__payment_required_verify_batch_short.json index 4506242..21c7df3 100644 --- a/tests/fixtures/parity/expected/errors__payment_required_verify_batch_short.json +++ b/tests/fixtures/parity/expected/errors__payment_required_verify_batch_short.json @@ -20,7 +20,7 @@ "remaining": 3, "request_id": "", "requested": 5, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "status_code": 402, "type": "LenzQuotaExceededError", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" diff --git a/tests/fixtures/parity/expected/errors__web_assess_payment_required.json b/tests/fixtures/parity/expected/errors__web_assess_payment_required.json new file mode 100644 index 0000000..04bef38 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__web_assess_payment_required.json @@ -0,0 +1,28 @@ +{ + "error": { + "cause": "No assessments left this month.", + "code": "no_credits", + "cost": 1, + "credit_balance": 0, + "doc_url": "https://lenz.io/docs/billing", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "friendly_text": "No assessments left this month.\n Fix: Top up or upgrade at https://lenz.io/plans, or wait for the period reset. See https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "message": "No assessments left this month.", + "payload_json": { + "error": { + "code": "no_credits", + "fix": "Top up or upgrade at https://lenz.io/plans, or wait for the period reset.", + "message": "No assessments left this month.", + "status": 402, + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } + }, + "remaining": 0, + "request_id": "", + "requested": null, + "resets_at": "2026-10-01T14:07:00+00:00", + "status_code": 402, + "type": "LenzQuotaExceededError", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" + } +} diff --git a/tests/fixtures/parity/expected/errors__web_assess_signup_required.json b/tests/fixtures/parity/expected/errors__web_assess_signup_required.json new file mode 100644 index 0000000..b16a7bb --- /dev/null +++ b/tests/fixtures/parity/expected/errors__web_assess_signup_required.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Sign up to check this — it’s free.", + "code": "signup_required", + "doc_url": "https://lenz.io/docs/auth", + "fix": "This key doesn't have access to that resource.", + "friendly_text": "Sign up to check this — it’s free.\n Fix: This key doesn't have access to that resource.", + "message": "Sign up to check this — it’s free.", + "payload_json": { + "error": { + "code": "unauthorized", + "fix": "This key doesn't have access to that resource.", + "message": "Sign up to check this — it’s free.", + "status": 403 + } + }, + "request_id": "", + "status_code": 403, + "type": "LenzAuthError" + } +} diff --git a/tests/fixtures/parity/expected/errors__web_review_rate_limited.json b/tests/fixtures/parity/expected/errors__web_review_rate_limited.json new file mode 100644 index 0000000..6841e77 --- /dev/null +++ b/tests/fixtures/parity/expected/errors__web_review_rate_limited.json @@ -0,0 +1,25 @@ +{ + "error": { + "cause": "This account has used its extractions for today. The daily allowance is shared with the Lenz API. It resets at 00:00 UTC.", + "code": "extract_daily_limit", + "doc_url": "https://lenz.io/docs/rate-limits", + "fix": "Wait Retry-After seconds and retry.", + "friendly_text": "This account has used its extractions for today. The daily allowance is shared with the Lenz API. It resets at 00:00 UTC.\n Fix: Wait Retry-After seconds and retry.", + "limit": 1000, + "message": "This account has used its extractions for today. The daily allowance is shared with the Lenz API. It resets at 00:00 UTC.", + "payload_json": { + "error": { + "code": "rate_limited", + "fix": "Wait Retry-After seconds and retry.", + "message": "This account has used its extractions for today. The daily allowance is shared with the Lenz API. It resets at 00:00 UTC.", + "status": 429 + } + }, + "request_id": "", + "reset_in_seconds": 777, + "retry_after": 777, + "status_code": 429, + "type": "LenzRateLimitError", + "upgrade_url": "https://lenz.io/plans" + } +} diff --git a/tests/fixtures/parity/expected/extract__focus_ready.json b/tests/fixtures/parity/expected/extract__focus_ready.json index 0b529b1..19a1965 100644 --- a/tests/fixtures/parity/expected/extract__focus_ready.json +++ b/tests/fixtures/parity/expected/extract__focus_ready.json @@ -19,6 +19,27 @@ "presumed_intent": "Verify reported figures", "status": "ready" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Beta fell 3% last year.", + "domain": "Economics", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, "render": "Claim: Beta fell 3% last year.\n\nVerify it: lenz verify \"Beta fell 3% last year.\"\n", - "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Beta fell 3% last year.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Beta fell 3% last year.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n", + "repr": "ExtractedClaims(status='ready', claim='Beta fell 3% last year.', identified_claims=[], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024. Beta fell 3% last year.', locations=None)" } diff --git a/tests/fixtures/parity/expected/extract__idempotency_replay.json b/tests/fixtures/parity/expected/extract__idempotency_replay.json index df61eab..91b0781 100644 --- a/tests/fixtures/parity/expected/extract__idempotency_replay.json +++ b/tests/fixtures/parity/expected/extract__idempotency_replay.json @@ -22,6 +22,30 @@ "presumed_intent": "Verify reported figures", "status": "ready" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n 2. Beta fell 3% last year.\n", - "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n", + "repr": "ExtractedClaims(status='ready', claim='Alpha rose 5% in 2024.', identified_claims=['Alpha rose 5% in 2024.', 'Beta fell 3% last year.'], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024. Beta fell 3% last year.', locations=None)" } diff --git a/tests/fixtures/parity/expected/extract__locate_all_dropped.json b/tests/fixtures/parity/expected/extract__locate_all_dropped.json index c015827..637c818 100644 --- a/tests/fixtures/parity/expected/extract__locate_all_dropped.json +++ b/tests/fixtures/parity/expected/extract__locate_all_dropped.json @@ -19,6 +19,27 @@ "presumed_intent": "Verify reported figures", "status": "not_a_claim" }, + "dump_unset": { + "candidate_claims": [], + "claim": "", + "domain": "", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": [], + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "not_a_claim" + }, "render": "No verifiable claim found in that text.\n", - "render_json": "{\n \"status\": \"not_a_claim\",\n \"claim\": \"\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": []\n}\n" + "render_json": "{\n \"status\": \"not_a_claim\",\n \"claim\": \"\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": []\n}\n", + "repr": "ExtractedClaims(status='not_a_claim', claim='', identified_claims=[], candidate_claims=[], domain='', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024. Beta fell 3% last year.', locations=[])" } diff --git a/tests/fixtures/parity/expected/extract__locate_failed.json b/tests/fixtures/parity/expected/extract__locate_failed.json index df61eab..91b0781 100644 --- a/tests/fixtures/parity/expected/extract__locate_failed.json +++ b/tests/fixtures/parity/expected/extract__locate_failed.json @@ -22,6 +22,30 @@ "presumed_intent": "Verify reported figures", "status": "ready" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n 2. Beta fell 3% last year.\n", - "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n", + "repr": "ExtractedClaims(status='ready', claim='Alpha rose 5% in 2024.', identified_claims=['Alpha rose 5% in 2024.', 'Beta fell 3% last year.'], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024. Beta fell 3% last year.', locations=None)" } diff --git a/tests/fixtures/parity/expected/extract__locate_leading_whitespace.json b/tests/fixtures/parity/expected/extract__locate_leading_whitespace.json index a007c40..cac302f 100644 --- a/tests/fixtures/parity/expected/extract__locate_leading_whitespace.json +++ b/tests/fixtures/parity/expected/extract__locate_leading_whitespace.json @@ -30,6 +30,38 @@ "presumed_intent": "Verify reported figures", "status": "ready" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "end": 25, + "start": 3, + "text": "Alpha rose 5% in 2024." + } + ] + } + ], + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, "render": "Claim: Alpha rose 5% in 2024.\n at 3-25: \"Alpha rose 5% in 2024.\"\n\nVerify it: lenz verify \"Alpha rose 5% in 2024.\"\n", - "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": 3,\n \"end\": 25,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n }\n ]\n}\n" + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": 3,\n \"end\": 25,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n }\n ]\n}\n", + "repr": "ExtractedClaims(status='ready', claim='Alpha rose 5% in 2024.', identified_claims=[], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024. Beta fell 3% last year.', locations=[ClaimLocation(claim='Alpha rose 5% in 2024.', positions=[Position(start=3, end=25, text='Alpha rose 5% in 2024.')])])" } diff --git a/tests/fixtures/parity/expected/extract__locate_some_dropped.json b/tests/fixtures/parity/expected/extract__locate_some_dropped.json index 80d25e1..09f3760 100644 --- a/tests/fixtures/parity/expected/extract__locate_some_dropped.json +++ b/tests/fixtures/parity/expected/extract__locate_some_dropped.json @@ -43,6 +43,51 @@ "presumed_intent": "Verify reported figures", "status": "ready" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "end": 22, + "start": 0, + "text": "Alpha rose 5% in 2024." + } + ] + }, + { + "claim": "Beta fell 3% last year.", + "positions": [ + { + "end": 46, + "start": 23, + "text": "Beta fell 3% last year." + } + ] + } + ], + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n at 0-22: \"Alpha rose 5% in 2024.\"\n 2. Beta fell 3% last year.\n at 23-46: \"Beta fell 3% last year.\"\n", - "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": 0,\n \"end\": 22,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n },\n {\n \"claim\": \"Beta fell 3% last year.\",\n \"positions\": [\n {\n \"start\": 23,\n \"end\": 46,\n \"text\": \"Beta fell 3% last year.\"\n }\n ]\n }\n ]\n}\n" + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": 0,\n \"end\": 22,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n },\n {\n \"claim\": \"Beta fell 3% last year.\",\n \"positions\": [\n {\n \"start\": 23,\n \"end\": 46,\n \"text\": \"Beta fell 3% last year.\"\n }\n ]\n }\n ]\n}\n", + "repr": "ExtractedClaims(status='ready', claim='Alpha rose 5% in 2024.', identified_claims=['Alpha rose 5% in 2024.', 'Beta fell 3% last year.'], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024. Beta fell 3% last year.', locations=[ClaimLocation(claim='Alpha rose 5% in 2024.', positions=[Position(start=0, end=22, text='Alpha rose 5% in 2024.')]), ClaimLocation(claim='Beta fell 3% last year.', positions=[Position(start=23, end=46, text='Beta fell 3% last year.')])])" } diff --git a/tests/fixtures/parity/expected/extract__locate_true.json b/tests/fixtures/parity/expected/extract__locate_true.json index 80d25e1..09f3760 100644 --- a/tests/fixtures/parity/expected/extract__locate_true.json +++ b/tests/fixtures/parity/expected/extract__locate_true.json @@ -43,6 +43,51 @@ "presumed_intent": "Verify reported figures", "status": "ready" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "end": 22, + "start": 0, + "text": "Alpha rose 5% in 2024." + } + ] + }, + { + "claim": "Beta fell 3% last year.", + "positions": [ + { + "end": 46, + "start": 23, + "text": "Beta fell 3% last year." + } + ] + } + ], + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n at 0-22: \"Alpha rose 5% in 2024.\"\n 2. Beta fell 3% last year.\n at 23-46: \"Beta fell 3% last year.\"\n", - "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": 0,\n \"end\": 22,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n },\n {\n \"claim\": \"Beta fell 3% last year.\",\n \"positions\": [\n {\n \"start\": 23,\n \"end\": 46,\n \"text\": \"Beta fell 3% last year.\"\n }\n ]\n }\n ]\n}\n" + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": 0,\n \"end\": 22,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n },\n {\n \"claim\": \"Beta fell 3% last year.\",\n \"positions\": [\n {\n \"start\": 23,\n \"end\": 46,\n \"text\": \"Beta fell 3% last year.\"\n }\n ]\n }\n ]\n}\n", + "repr": "ExtractedClaims(status='ready', claim='Alpha rose 5% in 2024.', identified_claims=['Alpha rose 5% in 2024.', 'Beta fell 3% last year.'], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024. Beta fell 3% last year.', locations=[ClaimLocation(claim='Alpha rose 5% in 2024.', positions=[Position(start=0, end=22, text='Alpha rose 5% in 2024.')]), ClaimLocation(claim='Beta fell 3% last year.', positions=[Position(start=23, end=46, text='Beta fell 3% last year.')])])" } diff --git a/tests/fixtures/parity/expected/extract__no_match_with_focus.json b/tests/fixtures/parity/expected/extract__no_match_with_focus.json index 8097b22..16a3c71 100644 --- a/tests/fixtures/parity/expected/extract__no_match_with_focus.json +++ b/tests/fixtures/parity/expected/extract__no_match_with_focus.json @@ -10,6 +10,18 @@ "presumed_intent": "", "status": "no_match" }, + "dump_unset": { + "candidate_claims": [], + "claim": "", + "domain": "", + "identified_claims": [], + "key_entities": [], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "", + "status": "no_match" + }, "render": "No claims matched the focus.\n", - "render_json": "{\n \"status\": \"no_match\",\n \"claim\": \"\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"\",\n \"key_entities\": [],\n \"presumed_intent\": \"\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" + "render_json": "{\n \"status\": \"no_match\",\n \"claim\": \"\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"\",\n \"key_entities\": [],\n \"presumed_intent\": \"\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n", + "repr": "ExtractedClaims(status='no_match', claim='', identified_claims=[], candidate_claims=[], domain='', key_entities=[], presumed_intent='', original_input='Alpha rose 5% in 2024. Beta fell 3% last year.', locations=None)" } diff --git a/tests/fixtures/parity/expected/extract__not_a_claim.json b/tests/fixtures/parity/expected/extract__not_a_claim.json index 1e7d7fe..48b365f 100644 --- a/tests/fixtures/parity/expected/extract__not_a_claim.json +++ b/tests/fixtures/parity/expected/extract__not_a_claim.json @@ -10,6 +10,18 @@ "presumed_intent": "", "status": "not_a_claim" }, + "dump_unset": { + "candidate_claims": [], + "claim": "", + "domain": "", + "identified_claims": [], + "key_entities": [], + "locations": null, + "original_input": "What a lovely day.", + "presumed_intent": "", + "status": "not_a_claim" + }, "render": "No verifiable claim found in that text.\n", - "render_json": "{\n \"status\": \"not_a_claim\",\n \"claim\": \"\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"\",\n \"key_entities\": [],\n \"presumed_intent\": \"\",\n \"original_input\": \"What a lovely day.\",\n \"locations\": null\n}\n" + "render_json": "{\n \"status\": \"not_a_claim\",\n \"claim\": \"\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"\",\n \"key_entities\": [],\n \"presumed_intent\": \"\",\n \"original_input\": \"What a lovely day.\",\n \"locations\": null\n}\n", + "repr": "ExtractedClaims(status='not_a_claim', claim='', identified_claims=[], candidate_claims=[], domain='', key_entities=[], presumed_intent='', original_input='What a lovely day.', locations=None)" } diff --git a/tests/fixtures/parity/expected/extract__not_a_claim_beside_claims.json b/tests/fixtures/parity/expected/extract__not_a_claim_beside_claims.json index 05550a3..13ec077 100644 --- a/tests/fixtures/parity/expected/extract__not_a_claim_beside_claims.json +++ b/tests/fixtures/parity/expected/extract__not_a_claim_beside_claims.json @@ -19,6 +19,27 @@ "presumed_intent": "Verify reported figures", "status": "not_a_claim" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024.", + "presumed_intent": "Verify reported figures", + "status": "not_a_claim" + }, "render": "Claim: Alpha rose 5% in 2024.\n\nVerify it: lenz verify \"Alpha rose 5% in 2024.\"\n", - "render_json": "{\n \"status\": \"not_a_claim\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024.\",\n \"locations\": null\n}\n" + "render_json": "{\n \"status\": \"not_a_claim\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024.\",\n \"locations\": null\n}\n", + "repr": "ExtractedClaims(status='not_a_claim', claim='Alpha rose 5% in 2024.', identified_claims=[], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024.', locations=None)" } diff --git a/tests/fixtures/parity/expected/extract__ready_one_claim.json b/tests/fixtures/parity/expected/extract__ready_one_claim.json index e65da3c..2f536e5 100644 --- a/tests/fixtures/parity/expected/extract__ready_one_claim.json +++ b/tests/fixtures/parity/expected/extract__ready_one_claim.json @@ -19,6 +19,27 @@ "presumed_intent": "Verify reported figures", "status": "ready" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, "render": "Claim: Alpha rose 5% in 2024.\n\nVerify it: lenz verify \"Alpha rose 5% in 2024.\"\n", - "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024.\",\n \"locations\": null\n}\n" + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024.\",\n \"locations\": null\n}\n", + "repr": "ExtractedClaims(status='ready', claim='Alpha rose 5% in 2024.', identified_claims=[], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024.', locations=None)" } diff --git a/tests/fixtures/parity/expected/extract__ready_several_claims.json b/tests/fixtures/parity/expected/extract__ready_several_claims.json index df61eab..91b0781 100644 --- a/tests/fixtures/parity/expected/extract__ready_several_claims.json +++ b/tests/fixtures/parity/expected/extract__ready_several_claims.json @@ -22,6 +22,30 @@ "presumed_intent": "Verify reported figures", "status": "ready" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n 2. Beta fell 3% last year.\n", - "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n", + "repr": "ExtractedClaims(status='ready', claim='Alpha rose 5% in 2024.', identified_claims=['Alpha rose 5% in 2024.', 'Beta fell 3% last year.'], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024. Beta fell 3% last year.', locations=None)" } diff --git a/tests/fixtures/parity/expected/extract__replay_later_200.json b/tests/fixtures/parity/expected/extract__replay_later_200.json index df61eab..91b0781 100644 --- a/tests/fixtures/parity/expected/extract__replay_later_200.json +++ b/tests/fixtures/parity/expected/extract__replay_later_200.json @@ -22,6 +22,30 @@ "presumed_intent": "Verify reported figures", "status": "ready" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [ + "Alpha rose 5% in 2024.", + "Beta fell 3% last year." + ], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": null, + "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, "render": "2 claims found:\n 1. Alpha rose 5% in 2024.\n 2. Beta fell 3% last year.\n", - "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n" + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [\n \"Alpha rose 5% in 2024.\",\n \"Beta fell 3% last year.\"\n ],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"Alpha rose 5% in 2024. Beta fell 3% last year.\",\n \"locations\": null\n}\n", + "repr": "ExtractedClaims(status='ready', claim='Alpha rose 5% in 2024.', identified_claims=['Alpha rose 5% in 2024.', 'Beta fell 3% last year.'], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='Alpha rose 5% in 2024. Beta fell 3% last year.', locations=None)" } diff --git a/tests/fixtures/parity/expected/extract__url_input_located.json b/tests/fixtures/parity/expected/extract__url_input_located.json index ca78e96..d928040 100644 --- a/tests/fixtures/parity/expected/extract__url_input_located.json +++ b/tests/fixtures/parity/expected/extract__url_input_located.json @@ -30,6 +30,38 @@ "presumed_intent": "Verify reported figures", "status": "ready" }, + "dump_unset": { + "candidate_claims": [], + "claim": "Alpha rose 5% in 2024.", + "domain": "Economics", + "identified_claims": [], + "key_entities": [ + { + "name": "Alpha", + "type": "organization" + }, + { + "name": "Beta", + "type": "organization" + } + ], + "locations": [ + { + "claim": "Alpha rose 5% in 2024.", + "positions": [ + { + "end": null, + "start": null, + "text": "Alpha rose 5% in 2024." + } + ] + } + ], + "original_input": "https://example.com/an-article", + "presumed_intent": "Verify reported figures", + "status": "ready" + }, "render": "Claim: Alpha rose 5% in 2024.\n at \"Alpha rose 5% in 2024.\"\n\nVerify it: lenz verify \"Alpha rose 5% in 2024.\"\n", - "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"https://example.com/an-article\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": null,\n \"end\": null,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n }\n ]\n}\n" + "render_json": "{\n \"status\": \"ready\",\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"identified_claims\": [],\n \"candidate_claims\": [],\n \"domain\": \"Economics\",\n \"key_entities\": [\n {\n \"name\": \"Alpha\",\n \"type\": \"organization\"\n },\n {\n \"name\": \"Beta\",\n \"type\": \"organization\"\n }\n ],\n \"presumed_intent\": \"Verify reported figures\",\n \"original_input\": \"https://example.com/an-article\",\n \"locations\": [\n {\n \"claim\": \"Alpha rose 5% in 2024.\",\n \"positions\": [\n {\n \"start\": null,\n \"end\": null,\n \"text\": \"Alpha rose 5% in 2024.\"\n }\n ]\n }\n ]\n}\n", + "repr": "ExtractedClaims(status='ready', claim='Alpha rose 5% in 2024.', identified_claims=[], candidate_claims=[], domain='Economics', key_entities=[ExtractedEntity(name='Alpha', type='organization'), ExtractedEntity(name='Beta', type='organization')], presumed_intent='Verify reported figures', original_input='https://example.com/an-article', locations=[ClaimLocation(claim='Alpha rose 5% in 2024.', positions=[Position(start=None, end=None, text='Alpha rose 5% in 2024.')])])" } diff --git a/tests/fixtures/parity/expected/review__402_no_credits.json b/tests/fixtures/parity/expected/review__402_no_credits.json index 6f8a31c..d6661c5 100644 --- a/tests/fixtures/parity/expected/review__402_no_credits.json +++ b/tests/fixtures/parity/expected/review__402_no_credits.json @@ -20,7 +20,7 @@ "remaining": 100, "request_id": "", "requested": null, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "status_code": 402, "type": "LenzQuotaExceededError", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" diff --git a/tests/fixtures/parity/expected/review__402_no_credits_exhausted.json b/tests/fixtures/parity/expected/review__402_no_credits_exhausted.json index c98a94a..75b0213 100644 --- a/tests/fixtures/parity/expected/review__402_no_credits_exhausted.json +++ b/tests/fixtures/parity/expected/review__402_no_credits_exhausted.json @@ -20,7 +20,7 @@ "remaining": 0, "request_id": "", "requested": null, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "status_code": 402, "type": "LenzQuotaExceededError", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" diff --git a/tests/fixtures/parity/expected/review__422_webhook_secret_missing.json b/tests/fixtures/parity/expected/review__422_webhook_secret_missing.json new file mode 100644 index 0000000..aa5a20c --- /dev/null +++ b/tests/fixtures/parity/expected/review__422_webhook_secret_missing.json @@ -0,0 +1,30 @@ +{ + "error": { + "cause": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "code": "webhook_secret_missing", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [ + { + "loc": [ + "body", + "webhook_url" + ], + "msg": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend." + } + ], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.\n Fix: Check the request body against the OpenAPI spec.", + "message": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/review__delete_not_a_route.json b/tests/fixtures/parity/expected/review__delete_not_a_route.json new file mode 100644 index 0000000..ebe2cee --- /dev/null +++ b/tests/fixtures/parity/expected/review__delete_not_a_route.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "HTTP 405", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "HTTP 405\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 405", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "HTTP 405", + "status": 405 + } + }, + "request_id": "", + "status_code": 405, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/review__get_assessing.json b/tests/fixtures/parity/expected/review__get_assessing.json index 72f3ffc..d03a95c 100644 --- a/tests/fixtures/parity/expected/review__get_assessing.json +++ b/tests/fixtures/parity/expected/review__get_assessing.json @@ -49,8 +49,110 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 10, + "review_id": "d6b2bd72", + "status": "assessing", + "summary": { + "assessments": { + "completed": 0, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "running", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": null, + "index": 0, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "running", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": null, + "index": 1, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -104,5 +206,6 @@ "exit_code": 2, "render": "Review d6b2bd72: assessing — 2 claims: 2 not checked · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n ? · quick check\n\n[2/2] Water boils at 100 C at sea level.\n ? · quick check\n", "render_issues": "Review d6b2bd72: assessing — 2 claims: 2 not checked · 2 credits charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='assessing', outcome=None, created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=0, failed=0), verifications=None, issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=10, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=None, assessment=ReviewAssessment(status='running', verdict=None, confidence=None, rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=None, verification=None, suggested_edits=None), ReviewClaim(index=1, claim='Water boils at 100 C at sea level.', positions=None, result=None, assessment=ReviewAssessment(status='running', verdict=None, confidence=None, rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=None, verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_assessment_rows_full_fields.json b/tests/fixtures/parity/expected/review__get_assessment_rows_full_fields.json index 8322f9e..04bcf67 100644 --- a/tests/fixtures/parity/expected/review__get_assessment_rows_full_fields.json +++ b/tests/fixtures/parity/expected/review__get_assessment_rows_full_fields.json @@ -68,8 +68,170 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 1, + "failure": { + "docs_url": null, + "failure_class": "upstream_unavailable", + "failure_reason": "timeout", + "hint": "The check ran out of time. Retry it; nothing was charged.", + "retryable": true + }, + "stage": "assessment" + } + ], + "issues": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "cap", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": null, + "rationale": "Two reviewers found the date wrong.", + "source": "assessment", + "suggested_edits": null, + "suggested_rewrite": "The EU AI Act entered into force in August 2024.", + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": null, + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "incomplete", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 0, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 1 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": "One reviewer read the claim as about the entry into force.", + "error_code": null, + "failure": null, + "hint": "This text holds more than one claim.", + "identified_claims": [ + "The EU AI Act took effect in 2024.", + "It took effect in March." + ], + "rationale": "Two reviewers found the date wrong.", + "status": "completed", + "suggested_rewrite": "The EU AI Act entered into force in August 2024.", + "verdict": "False", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "cap", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "assessment", + "verdict": "False" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": "timeout", + "failure": { + "docs_url": null, + "failure_class": "upstream_unavailable", + "failure_reason": "timeout", + "hint": "The check ran out of time. Retry it; nothing was charged.", + "retryable": true + }, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "failed", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": null, + "index": 1, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -164,5 +326,6 @@ "exit_code": 2, "render": "Review d6b2bd72: incomplete — 2 claims: 1 issue, 1 failed · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n Two reviewers found the date wrong.\n Not deep-checked (cap).\n\n[2/2] The Eiffel Tower is in Berlin.\n Quick check failed: The check ran out of time. Retry it; nothing was charged.\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", "render_issues": "Review d6b2bd72: incomplete — 2 claims: 1 issue, 1 failed · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n Two reviewers found the date wrong.\n Suggested rewrite: The EU AI Act entered into force in August 2024.\n Not deep-checked (cap).\n\n[2/2] The Eiffel Tower is in Berlin.\n Assessment failed: The check ran out of time. Retry it; nothing was charged.\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='incomplete', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=0, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=1), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=1, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[ReviewIssue(claim_index=0, claim='The EU AI Act took effect in March 2024.', verified_claim=None, verdict='False', confidence='high', source='assessment', verification_id=None, verification_status=None, verification_url=None, url=None, escalation=Escalation(matched_rules=['verdict'], disposition='cap'), key_finding=None, rationale='Two reviewers found the date wrong.', suggested_rewrite='The EU AI Act entered into force in August 2024.', failure=None, suggested_edits=None)], failures=[ReviewFailure(claim_index=1, claim='The Eiffel Tower is in Berlin.', stage='assessment', failure=FailureBlock(failure_reason='timeout', failure_class='upstream_unavailable', retryable=True, hint='The check ran out of time. Retry it; nothing was charged.', docs_url=None))], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='False', confidence='high', source='assessment', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='False', confidence='high', rationale='Two reviewers found the date wrong.', dissent='One reviewer read the claim as about the entry into force.', verification_url=None, error_code=None, identified_claims=['The EU AI Act took effect in 2024.', 'It took effect in March.'], hint='This text holds more than one claim.', suggested_rewrite='The EU AI Act entered into force in August 2024.', failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='cap'), verification=None, suggested_edits=None), ReviewClaim(index=1, claim='The Eiffel Tower is in Berlin.', positions=None, result=None, assessment=ReviewAssessment(status='failed', verdict=None, confidence=None, rationale=None, dissent=None, verification_url=None, error_code='timeout', identified_claims=[], hint=None, suggested_rewrite=None, failure=FailureBlock(failure_reason='timeout', failure_class='upstream_unavailable', retryable=True, hint='The check ran out of time. Retry it; nothing was charged.', docs_url=None)), escalation=None, verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_clean.json b/tests/fixtures/parity/expected/review__get_citations_clean.json index b9ecbce..403f0e1 100644 --- a/tests/fixtures/parity/expected/review__get_citations_clean.json +++ b/tests/fixtures/parity/expected/review__get_citations_clean.json @@ -114,8 +114,183 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 3 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 3 }, @@ -177,5 +352,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n2 checked.\n", "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n2 checked.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=2, citations_selected=2, citation_limit=20, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=3), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=Position(start=111, end=178, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_failed_and_unchecked.json b/tests/fixtures/parity/expected/review__get_citations_failed_and_unchecked.json index 81f36b2..b12ff7d 100644 --- a/tests/fixtures/parity/expected/review__get_citations_failed_and_unchecked.json +++ b/tests/fixtures/parity/expected/review__get_citations_failed_and_unchecked.json @@ -130,8 +130,199 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "incomplete", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 0, + "failed": 1, + "unchecked": 1 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#internal", + "failure_class": "internal", + "failure_reason": "internal", + "hint": "The check failed on our side. Try again later.", + "retryable": false + }, + "reference": "a report from the ministry" + } + ], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#internal", + "failure_class": "internal", + "failure_reason": "internal", + "hint": "The check failed on our side. Try again later.", + "retryable": false + }, + "hint": "The check failed on our side. Try again later.", + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "failed", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": null, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": null, + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "unchecked", + "unchecked_reason": "no_text" + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "unchecked", + "is_issue": false, + "source": null + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -193,5 +384,6 @@ "exit_code": 2, "render": "Review d6b2bd72: incomplete — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n2 could not be checked.\n\n[source 1/2] Could not be checked this time.\n https://example.gov/report-2024\n The check failed on our side. Try again later.\n\nCheck these by hand (Lenz could not check them)\n[source 2/2] The page gave no text to read.\n https://example.org/statement\n", "render_issues": "Review d6b2bd72: incomplete — 1 claim: 1 true or mostly true · 1 credit charged\n\n2 sources cited in your draft\n2 could not be checked.\n\n[source 1/2] Could not be checked this time.\n https://example.gov/report-2024\n The check failed on our side. Try again later.\n\nCheck these by hand (Lenz could not check them)\n[source 2/2] The page gave no text to read.\n https://example.org/statement\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='incomplete', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=2, citations_selected=2, citation_limit=20, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=0, unchecked=1, failed=1), citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=1), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[ReviewCitationFailure(citation_index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, failure=FailureBlock(failure_reason='internal', failure_class='internal', retryable=False, hint='The check failed on our side. Try again later.', docs_url='https://lenz.io/docs/errors#internal'))], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=None, check=ReviewCitationCheck(status='failed', page_read=None, page_title=None, page_published_date=None, page_language=None, source_url=None, source_version=None, support=None, snippet=None, rationale=None, quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint='The check failed on our side. Try again later.', failure=FailureBlock(failure_reason='internal', failure_class='internal', retryable=False, hint='The check failed on our side. Try again later.', docs_url='https://lenz.io/docs/errors#internal'))), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=Position(start=111, end=178, text=None), result=ReviewCitationResult(finding='unchecked', source=None, is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='unchecked', snippet=None, rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason='no_text', hint=None, failure=None))])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_issue_full.json b/tests/fixtures/parity/expected/review__get_citations_issue_full.json index cbb418a..558e623 100644 --- a/tests/fixtures/parity/expected/review__get_citations_issue_full.json +++ b/tests/fixtures/parity/expected/review__get_citations_issue_full.json @@ -136,8 +136,205 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 3 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 1, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": null, + "finding": "contradicted", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "rationale": "The page states it.", + "reference": "a report from the ministry", + "snippet": "The source says so.", + "source": "support", + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + } + ], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "contradicted", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "contradicted", + "is_issue": true, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 3 }, @@ -199,5 +396,6 @@ "exit_code": 1, "render": "Review d6b2bd72: issues found — 1 claim: 1 true or mostly true · 3 credits charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n2 checked, 1 with a problem.\n\n[source 1/2] Contradicted\n Unemployment fell to 4.1% in 2024, according to a report from the ministry.\n https://example.gov/report-2024\n The source says:\n “The source says so.”\n Reviewer's note: The page states it.\n\nA reviewer's note is reasoning, not a checked source; the quoted passage is from the page.\n", "render_issues": "Review d6b2bd72: issues found — 1 claim: 1 true or mostly true · 3 credits charged\n\n2 sources cited in your draft\n2 checked, 1 with a problem.\n\n[source 1/2] Contradicted\n Unemployment fell to 4.1% in 2024, according to a report from the ministry.\n https://example.gov/report-2024\n The source says:\n “The source says so.”\n Reviewer's note: The page states it.\n\nA reviewer's note is reasoning, not a checked source; the quoted passage is from the page.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='issues_found', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=2, citations_selected=2, citation_limit=20, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=1, citations_skipped=None), credits=ReviewCredits(charged=3), poll_after_seconds=None, issues=[], failures=[], citation_issues=[ReviewCitationIssue(citation_index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), finding='contradicted', source='support', snippet='The source says so.', rationale='The page states it.', missing_quote=None, metadata_differences=[], page_title='Page at https://example.gov/report-2024', failure=None)], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=ReviewCitationResult(finding='contradicted', source='support', is_issue=True), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='contradicted', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=Position(start=111, end=178, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_issue_issues_view.json b/tests/fixtures/parity/expected/review__get_citations_issue_issues_view.json index 59abdb7..99f5e5f 100644 --- a/tests/fixtures/parity/expected/review__get_citations_issue_issues_view.json +++ b/tests/fixtures/parity/expected/review__get_citations_issue_issues_view.json @@ -26,8 +26,93 @@ ], "citations": [], "claims": [], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 3 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 1, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "issues" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [ + { + "citation_index": 0, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "failure": null, + "finding": "contradicted", + "metadata_differences": [], + "missing_quote": null, + "page_title": "Page at https://example.gov/report-2024", + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "rationale": "The page states it.", + "reference": "a report from the ministry", + "snippet": "The source says so.", + "source": "support", + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 3 }, @@ -89,5 +174,6 @@ "exit_code": 1, "render": "Review d6b2bd72: issues found — 1 claim: 1 not checked · 3 credits charged\n\n2 sources cited in your draft\n2 checked, 1 with a problem.\n\n[source 1/2] Contradicted\n Unemployment fell to 4.1% in 2024, according to a report from the ministry.\n https://example.gov/report-2024\n The source says:\n “The source says so.”\n Reviewer's note: The page states it.\n\nA reviewer's note is reasoning, not a checked source; the quoted passage is from the page.\n", "render_issues": "Review d6b2bd72: issues found — 1 claim: 1 not checked · 3 credits charged\n\n2 sources cited in your draft\n2 checked, 1 with a problem.\n\n[source 1/2] Contradicted\n Unemployment fell to 4.1% in 2024, according to a report from the ministry.\n https://example.gov/report-2024\n The source says:\n “The source says so.”\n Reviewer's note: The page states it.\n\nA reviewer's note is reasoning, not a checked source; the quoted passage is from the page.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='issues', status='completed', outcome='issues_found', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=2, citations_selected=2, citation_limit=20, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=1, citations_skipped=None), credits=ReviewCredits(charged=3), poll_after_seconds=None, issues=[], failures=[], citation_issues=[ReviewCitationIssue(citation_index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), finding='contradicted', source='support', snippet='The source says so.', rationale='The page states it.', missing_quote=None, metadata_differences=[], page_title='Page at https://example.gov/report-2024', failure=None)], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_limit_exactly_at_limit.json b/tests/fixtures/parity/expected/review__get_citations_limit_exactly_at_limit.json index 21955f5..d8c2878 100644 --- a/tests/fixtures/parity/expected/review__get_citations_limit_exactly_at_limit.json +++ b/tests/fixtures/parity/expected/review__get_citations_limit_exactly_at_limit.json @@ -114,8 +114,183 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 3 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 2, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 2, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 3 }, @@ -177,5 +352,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n2 checked.\n", "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n2 checked.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=2, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=2, citations_selected=2, citation_limit=2, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=3), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=Position(start=111, end=178, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_limit_reached.json b/tests/fixtures/parity/expected/review__get_citations_limit_reached.json index 5e3bb88..8a1c54a 100644 --- a/tests/fixtures/parity/expected/review__get_citations_limit_reached.json +++ b/tests/fixtures/parity/expected/review__get_citations_limit_reached.json @@ -75,8 +75,157 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [ + { + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "reference": "a statement", + "sentence": "The agency said so in a statement." + } + ], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 1, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 1, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 1, + "citation_limit_reached": true, + "citations_found": 2, + "citations_selected": 1, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -151,5 +300,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 2 credits charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n1 checked.\n1 more was not checked: one check covers 1.\n\n1 more citation was found but not checked.\n", "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 2 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n1 checked.\n1 more was not checked: one check covers 1.\n\n1 more citation was found but not checked.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=1, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=2, citations_selected=1, citation_limit=1, citation_limit_reached=True, citation_checks=ReviewCitationCheckCounts(checked=1, unchecked=0, failed=0), citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[ReviewMoreCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, sentence='The agency said so in a statement.', position=Position(start=111, end=178, text=None))], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_no_claim_but_citations.json b/tests/fixtures/parity/expected/review__get_citations_no_claim_but_citations.json index 8093baf..d2bf7e8 100644 --- a/tests/fixtures/parity/expected/review__get_citations_no_claim_but_citations.json +++ b/tests/fixtures/parity/expected/review__get_citations_no_claim_but_citations.json @@ -83,8 +83,152 @@ } ], "claims": [], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 0, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 0, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -146,5 +290,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — no claims checked · 2 credits charged\n\n2 sources cited in your draft\n2 checked.\n", "render_issues": "Review d6b2bd72: clean — no claims checked · 2 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n2 checked.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=0, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=0, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=2, citations_selected=2, citation_limit=20, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[], citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=Position(start=111, end=178, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_no_claim_no_citation.json b/tests/fixtures/parity/expected/review__get_citations_no_claim_no_citation.json index c088cac..74da78d 100644 --- a/tests/fixtures/parity/expected/review__get_citations_no_claim_no_citation.json +++ b/tests/fixtures/parity/expected/review__get_citations_no_claim_no_citation.json @@ -4,8 +4,68 @@ "citation_issues": [], "citations": [], "claims": [], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "no_claim", + "hint": "No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.", + "retryable": false + }, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": "unchecked", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "failed", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -62,5 +122,6 @@ "exit_code": 2, "render": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run\nthe text through /extract to enumerate its claims.\n", "render_issues": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run\nthe text through /extract to enumerate its claims.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='failed', outcome='unchecked', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=None, claim_limit=20, claim_limit_reached=None, input_truncated=False, assessments=None, verifications=None, issues=0, citations_found=None, citations_selected=None, citation_limit=20, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=0), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=None, more_claim_locations=None, more_citations=None, failure=FailureBlock(failure_reason='no_claim', failure_class='invalid_input', retryable=False, hint='No factual statement that can be checked against evidence was found in the input. Send one factual claim, or run the text through /extract to enumerate its claims.', docs_url='https://lenz.io/docs/errors#invalid-input'), claims=[], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_not_asked.json b/tests/fixtures/parity/expected/review__get_citations_not_asked.json index a7c1d4a..b0e08d1 100644 --- a/tests/fixtures/parity/expected/review__get_citations_not_asked.json +++ b/tests/fixtures/parity/expected/review__get_citations_not_asked.json @@ -35,8 +35,100 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -94,5 +186,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=1), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_only.json b/tests/fixtures/parity/expected/review__get_citations_only.json index ec2968f..7b79f80 100644 --- a/tests/fixtures/parity/expected/review__get_citations_only.json +++ b/tests/fixtures/parity/expected/review__get_citations_only.json @@ -83,8 +83,159 @@ } ], "claims": [], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "positions": null + } + ], + "more_claims": [ + "The EU AI Act took effect in March 2024." + ], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 0, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 0, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 0, + "claim_limit_reached": true, + "claims_selected": 0, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -153,5 +304,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — no claims checked · 2 credits charged\n\n2 sources cited in your draft\n2 checked.\n\n1 more claim was found but not checked.\n", "render_issues": "Review d6b2bd72: clean — no claims checked · 2 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n2 checked.\n\n1 more claim was found but not checked.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=0, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=0, claim_limit=0, claim_limit_reached=True, input_truncated=False, assessments=ReviewAssessmentCounts(completed=0, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=2, citations_selected=2, citation_limit=20, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=['The EU AI Act took effect in March 2024.'], more_claim_locations=[ClaimLocation(claim='The EU AI Act took effect in March 2024.', positions=None)], more_citations=[], failure=None, claims=[], citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=Position(start=111, end=178, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_partly_supported.json b/tests/fixtures/parity/expected/review__get_citations_partly_supported.json index 1f7c6fc..144016b 100644 --- a/tests/fixtures/parity/expected/review__get_citations_partly_supported.json +++ b/tests/fixtures/parity/expected/review__get_citations_partly_supported.json @@ -114,8 +114,183 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 3 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 2, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.gov/report-2024", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.gov/report-2024", + "source_version": null, + "status": "completed", + "support": "partly_supported", + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": { + "end": 110, + "start": 0, + "text": null + }, + "quotes": [], + "reference": "a report from the ministry", + "result": { + "finding": "partly_supported", + "is_issue": false, + "source": "support" + }, + "statement": "Unemployment fell to 4.1% in 2024, according to a report from the ministry." + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": "en", + "page_published_date": null, + "page_read": "full", + "page_title": "Page at https://example.org/statement", + "quote": null, + "rationale": "The page states it.", + "registered": null, + "snippet": "The source says so.", + "source_url": "https://example.org/statement", + "source_version": null, + "status": "completed", + "support": "supported", + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": { + "end": 178, + "start": 111, + "text": null + }, + "quotes": [], + "reference": "a statement", + "result": { + "finding": "supported", + "is_issue": false, + "source": "support" + }, + "statement": "The agency said so in a statement." + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 3 }, @@ -177,5 +352,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\n2 checked.\n", "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 3 credits charged\n\nNo issues.\n\n2 sources cited in your draft\n2 checked.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=2, citations_selected=2, citation_limit=20, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=2, unchecked=0, failed=0), citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=3), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement='Unemployment fell to 4.1% in 2024, according to a report from the ministry.', quotes=[], position=Position(start=0, end=110, text=None), result=ReviewCitationResult(finding='partly_supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.gov/report-2024', page_published_date=None, page_language='en', source_url='https://example.gov/report-2024', source_version=None, support='partly_supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement='The agency said so in a statement.', quotes=[], position=Position(start=111, end=178, text=None), result=ReviewCitationResult(finding='supported', source='support', is_issue=False), check=ReviewCitationCheck(status='completed', page_read='full', page_title='Page at https://example.org/statement', page_published_date=None, page_language='en', source_url='https://example.org/statement', source_version=None, support='supported', snippet='The source says so.', rationale='The page states it.', quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_running.json b/tests/fixtures/parity/expected/review__get_citations_running.json index 197c7ad..acc4c84 100644 --- a/tests/fixtures/parity/expected/review__get_citations_running.json +++ b/tests/fixtures/parity/expected/review__get_citations_running.json @@ -99,7 +99,166 @@ } ], "completed_at": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 15, + "review_id": "d6b2bd72", + "status": "verifying", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": { + "checked": 0, + "failed": 0, + "unchecked": 0 + }, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": false, + "citations_found": 2, + "citations_selected": 2, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [ + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "pending", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.gov/report-2024", + "doi": null, + "index": 0, + "position": null, + "quotes": [], + "reference": "a report from the ministry", + "result": null, + "statement": null + }, + { + "check": { + "doi_registered": null, + "failure": null, + "hint": null, + "metadata": null, + "metadata_differences": [], + "missing_quote": null, + "page_language": null, + "page_published_date": null, + "page_read": null, + "page_title": null, + "quote": null, + "rationale": null, + "registered": null, + "snippet": null, + "source_url": null, + "source_version": null, + "status": "pending", + "support": null, + "unchecked_reason": null + }, + "cited_url": "https://example.org/statement", + "doi": null, + "index": 1, + "position": null, + "quotes": [], + "reference": "a statement", + "result": null, + "statement": null + } + ], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": null, + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -161,5 +320,6 @@ "exit_code": 2, "render": "Review d6b2bd72: verifying — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n2 sources cited in your draft\nLenz checks each one: does the source say what your draft says it does.\n", "render_issues": "Review d6b2bd72: verifying — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n\n2 sources cited in your draft\nLenz checks each one: does the source say what your draft says it does.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='verifying', outcome=None, created_at='2026-10-01T09:07:00.123456Z', completed_at=None, language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=2, citations_selected=2, citation_limit=20, citation_limit_reached=False, citation_checks=ReviewCitationCheckCounts(checked=0, unchecked=0, failed=0), citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=1), poll_after_seconds=15, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[ReviewCitation(index=0, reference='a report from the ministry', cited_url='https://example.gov/report-2024', doi=None, statement=None, quotes=[], position=None, result=None, check=ReviewCitationCheck(status='pending', page_read=None, page_title=None, page_published_date=None, page_language=None, source_url=None, source_version=None, support=None, snippet=None, rationale=None, quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None)), ReviewCitation(index=1, reference='a statement', cited_url='https://example.org/statement', doi=None, statement=None, quotes=[], position=None, result=None, check=ReviewCitationCheck(status='pending', page_read=None, page_title=None, page_published_date=None, page_language=None, source_url=None, source_version=None, support=None, snippet=None, rationale=None, quote=None, missing_quote=None, doi_registered=None, metadata=None, metadata_differences=[], registered=None, unchecked_reason=None, hint=None, failure=None))])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_skipped_switched_off.json b/tests/fixtures/parity/expected/review__get_citations_skipped_switched_off.json index 9656e4e..bac0fa1 100644 --- a/tests/fixtures/parity/expected/review__get_citations_skipped_switched_off.json +++ b/tests/fixtures/parity/expected/review__get_citations_skipped_switched_off.json @@ -35,8 +35,100 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": "switched_off", + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -94,5 +186,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=20, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped='switched_off'), credits=ReviewCredits(charged=1), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_citations_skipped_url_input.json b/tests/fixtures/parity/expected/review__get_citations_skipped_url_input.json index 4a4d436..f74fcd2 100644 --- a/tests/fixtures/parity/expected/review__get_citations_skipped_url_input.json +++ b/tests/fixtures/parity/expected/review__get_citations_skipped_url_input.json @@ -4,8 +4,68 @@ "citation_issues": [], "citations": [], "claims": [], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": null, + "retryable": true + }, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": "unchecked", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 20, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "failed", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": 20, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": "url_input", + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -62,5 +122,6 @@ "exit_code": 2, "render": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: upstream_unavailable\n\nSources on a linked page are not checked. Paste the page's text instead to check them.\n", "render_issues": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: upstream_unavailable\n\nSources on a linked page are not checked. Paste the page's text instead to check them.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='failed', outcome='unchecked', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=20, suggest_edits=False), summary=ReviewSummary(claims_selected=None, claim_limit=20, claim_limit_reached=None, input_truncated=False, assessments=None, verifications=None, issues=0, citations_found=None, citations_selected=None, citation_limit=20, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped='url_input'), credits=ReviewCredits(charged=0), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=None, more_claim_locations=None, more_citations=None, failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint=None, docs_url='https://lenz.io/docs/errors#upstream-unavailable'), claims=[], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_claim_limit_not_reached.json b/tests/fixtures/parity/expected/review__get_claim_limit_not_reached.json index fe88fdc..b544e5b 100644 --- a/tests/fixtures/parity/expected/review__get_claim_limit_not_reached.json +++ b/tests/fixtures/parity/expected/review__get_claim_limit_not_reached.json @@ -65,8 +65,130 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 3, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 3, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -124,5 +246,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n[2/2] Water boils at 100 C at sea level.\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=3, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=3, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=2, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None), ReviewClaim(index=1, claim='Water boils at 100 C at sea level.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_claim_limit_reached_exact.json b/tests/fixtures/parity/expected/review__get_claim_limit_reached_exact.json index 50f547c..d282376 100644 --- a/tests/fixtures/parity/expected/review__get_claim_limit_reached_exact.json +++ b/tests/fixtures/parity/expected/review__get_claim_limit_reached_exact.json @@ -65,8 +65,130 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 2, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 2, + "claim_limit_reached": true, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -124,5 +246,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n[2/2] Water boils at 100 C at sea level.\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=2, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=2, claim_limit_reached=True, input_truncated=False, assessments=ReviewAssessmentCounts(completed=2, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None), ReviewClaim(index=1, claim='Water boils at 100 C at sea level.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_completed_assess_only.json b/tests/fixtures/parity/expected/review__get_completed_assess_only.json index 382a665..ffc8ab2 100644 --- a/tests/fixtures/parity/expected/review__get_completed_assess_only.json +++ b/tests/fixtures/parity/expected/review__get_completed_assess_only.json @@ -67,8 +67,156 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 1, + "confidence": "high", + "escalation": { + "disposition": "cap", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": null, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": null, + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 0, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "cap", + "matched_rules": [ + "verdict" + ] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "assessment", + "verdict": "False" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -150,5 +298,6 @@ "exit_code": 1, "render": "Review d6b2bd72: issues found — 2 claims: 1 issue, 1 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n[2/2] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Not deep-checked (cap).\n", "render_issues": "Review d6b2bd72: issues found — 2 claims: 1 issue, 1 true or mostly true · 2 credits charged\n\n[2/2] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Not deep-checked (cap).\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='issues_found', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=0, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=2, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=1, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[ReviewIssue(claim_index=1, claim='The Eiffel Tower is in Berlin.', verified_claim=None, verdict='False', confidence='high', source='assessment', verification_id=None, verification_status=None, verification_url=None, url=None, escalation=Escalation(matched_rules=['verdict'], disposition='cap'), key_finding=None, rationale=None, suggested_rewrite=None, failure=None, suggested_edits=None)], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None), ReviewClaim(index=1, claim='The Eiffel Tower is in Berlin.', positions=None, result=ReviewResult(verdict='False', confidence='high', source='assessment', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='False', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='cap'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_completed_clean.json b/tests/fixtures/parity/expected/review__get_completed_clean.json index b028662..9ff4a6b 100644 --- a/tests/fixtures/parity/expected/review__get_completed_clean.json +++ b/tests/fixtures/parity/expected/review__get_completed_clean.json @@ -65,8 +65,130 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Paris is the capital of France.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -124,5 +246,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n True (high) · quick check\n\n[2/2] Paris is the capital of France.\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=2, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None), ReviewClaim(index=1, claim='Paris is the capital of France.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_completed_issues_all_verified.json b/tests/fixtures/parity/expected/review__get_completed_issues_all_verified.json index aa86f83..80599b7 100644 --- a/tests/fixtures/parity/expected/review__get_completed_issues_all_verified.json +++ b/tests/fixtures/parity/expected/review__get_completed_issues_all_verified.json @@ -38,7 +38,7 @@ "claim": "The EU AI Act took effect in March 2024.", "confidence": "high", "content_status": "available", - "created_at": "2026-10-01T09:49:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "depth": "standard", "domain": "", "entities": [], @@ -50,11 +50,11 @@ "modified_at": null, "status": "completed", "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", - "task_id": "c010dca9a43543f518e49f4ec7842ceb", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "b4e2e99d", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "visibility": "private", "warnings": [ "w1" @@ -95,7 +95,7 @@ "claim": "The Eiffel Tower is in Berlin.", "confidence": "high", "content_status": "available", - "created_at": "2026-10-01T09:49:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "depth": "standard", "domain": "", "entities": [], @@ -107,11 +107,11 @@ "modified_at": null, "status": "completed", "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "task_id": "4634b89821fd877f1edf8aaeb82b7ee5", - "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "url": "https://lenz.io/c/the-earth-is-round-4d44dfaf", "verdict": "False", - "verification_id": "b79019e4", - "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", + "verification_id": "4d44dfaf", + "verification_url": "https://lenz.io/api/v1/verifications/4d44dfaf", "visibility": "private", "warnings": [ "w1" @@ -149,8 +149,8 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 23 }, @@ -173,11 +173,11 @@ "source": "verification", "suggested_edits": null, "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "verified_claim": null }, { @@ -196,11 +196,264 @@ "source": "verification", "suggested_edits": null, "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "url": "https://lenz.io/c/the-earth-is-round-4d44dfaf", "verdict": "False", - "verification_id": "b79019e4", + "verification_id": "4d44dfaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", + "verification_url": "https://lenz.io/api/v1/verifications/4d44dfaf", + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 3, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 3, + "input_truncated": false, + "issues": 2, + "verifications": { + "completed": 2, + "failed": 0, + "planned": 2 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "medium", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "Mostly False", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The EU AI Act took effect in March 2024.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The EU AI Act took effect in March 2024.", + "failure": null, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "visibility": "private", + "warnings": [ + "w1" + ] + } + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "url": "https://lenz.io/c/the-earth-is-round-4d44dfaf", + "verdict": "False", + "verification_id": "4d44dfaf", + "verification_url": "https://lenz.io/api/v1/verifications/4d44dfaf", + "visibility": "private", + "warnings": [ + "w1" + ] + } + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Paris is the capital of France.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 2, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 23 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "verified_claim": null + }, + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 1, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-4d44dfaf", + "verdict": "False", + "verification_id": "4d44dfaf", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/4d44dfaf", "verified_claim": null } ], @@ -253,7 +506,8 @@ "view": "full" }, "exit_code": 1, - "render": "Review d6b2bd72: issues found — 3 claims: 2 issues, 1 true or mostly true · 2 of 2 deep-checked · 23 credits charged\n\n[1/3] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\n[2/3] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b79019e4\n\n[3/3] Paris is the capital of France.\n True (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_issues": "Review d6b2bd72: issues found — 3 claims: 2 issues, 1 true or mostly true · 2 of 2 deep-checked · 23 credits charged\n\n[1/3] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\n[2/3] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b79019e4\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_json": null + "render": "Review d6b2bd72: issues found — 3 claims: 2 issues, 1 true or mostly true · 2 of 2 deep-checked · 23 credits charged\n\n[1/3] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\n[2/3] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-4d44dfaf\n\n[3/3] Paris is the capital of France.\n True (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: issues found — 3 claims: 2 issues, 1 true or mostly true · 2 of 2 deep-checked · 23 credits charged\n\n[1/3] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\n[2/3] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-4d44dfaf\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='issues_found', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=3, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=3, failed=0), verifications=ReviewVerificationCounts(planned=2, completed=2, failed=0), issues=2, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=23), poll_after_seconds=None, issues=[ReviewIssue(claim_index=0, claim='The EU AI Act took effect in March 2024.', verified_claim=None, verdict='False', confidence='high', source='verification', verification_id='68ca4aaf', verification_status='completed', verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding='Finding for The EU AI Act took effect in March 2024.', rationale=None, suggested_rewrite='Fixed: The EU AI Act took effect in March 2024.', failure=None, suggested_edits=None), ReviewIssue(claim_index=1, claim='The Eiffel Tower is in Berlin.', verified_claim=None, verdict='False', confidence='high', source='verification', verification_id='4d44dfaf', verification_status='completed', verification_url='https://lenz.io/api/v1/verifications/4d44dfaf', url='https://lenz.io/c/the-earth-is-round-4d44dfaf', escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding='Finding for The Eiffel Tower is in Berlin.', rationale=None, suggested_rewrite='Fixed: The Eiffel Tower is in Berlin.', failure=None, suggested_edits=None)], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='False', confidence='high', source='verification', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='Mostly False', confidence='medium', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='planned'), verification=ReviewVerification(status='completed', content_status='available', verification_id='68ca4aaf', task_id='7cff18da2d979d6370e54a160be121ad', claim='The EU AI Act took effect in March 2024.', language='en', visibility='private', depth='standard', domain='', entities=[], verdict='False', confidence='high', lenz_score=2, key_finding='Finding for The EU AI Act took effect in March 2024.', executive_summary='Summary for The EU AI Act took effect in March 2024.', suggested_rewrite='Fixed: The EU AI Act took effect in March 2024.', warnings=['w1'], created_at='2026-10-01T09:14:00.123456+00:00', modified_at=None, verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', failure=None), suggested_edits=None), ReviewClaim(index=1, claim='The Eiffel Tower is in Berlin.', positions=None, result=ReviewResult(verdict='False', confidence='high', source='verification', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='False', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='planned'), verification=ReviewVerification(status='completed', content_status='available', verification_id='4d44dfaf', task_id='0b92b443eb69b9c71434fdc64f2ca8be', claim='The Eiffel Tower is in Berlin.', language='en', visibility='private', depth='standard', domain='', entities=[], verdict='False', confidence='high', lenz_score=2, key_finding='Finding for The Eiffel Tower is in Berlin.', executive_summary='Summary for The Eiffel Tower is in Berlin.', suggested_rewrite='Fixed: The Eiffel Tower is in Berlin.', warnings=['w1'], created_at='2026-10-01T09:14:00.123456+00:00', modified_at=None, verification_url='https://lenz.io/api/v1/verifications/4d44dfaf', url='https://lenz.io/c/the-earth-is-round-4d44dfaf', failure=None), suggested_edits=None), ReviewClaim(index=2, claim='Paris is the capital of France.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_completed_issues_full.json b/tests/fixtures/parity/expected/review__get_completed_issues_full.json index b2bfc03..58214d0 100644 --- a/tests/fixtures/parity/expected/review__get_completed_issues_full.json +++ b/tests/fixtures/parity/expected/review__get_completed_issues_full.json @@ -38,7 +38,7 @@ "claim": "The EU AI Act took effect in March 2024.", "confidence": "high", "content_status": "available", - "created_at": "2026-10-01T09:42:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "depth": "standard", "domain": "", "entities": [], @@ -50,11 +50,11 @@ "modified_at": null, "status": "completed", "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", - "task_id": "7df4009bc27aab64ce5d5a01fbafe599", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "b4e2e99d", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "visibility": "private", "warnings": [ "w1" @@ -141,7 +141,7 @@ "modified_at": null, "status": "failed", "suggested_rewrite": null, - "task_id": "5ccac77f53ff49328ec134fb29d66542", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", "url": null, "verdict": null, "verification_id": null, @@ -181,8 +181,8 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 13 }, @@ -218,11 +218,315 @@ "source": "verification", "suggested_edits": null, "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "verified_claim": null + }, + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 2, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "hint": null, + "retryable": false + }, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": null, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": "failed", + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "incomplete", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 3, + "failed": 1 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 4, + "input_truncated": false, + "issues": 2, + "verifications": { + "completed": 1, + "failed": 1, + "planned": 2 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "medium", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "Mostly False", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The EU AI Act took effect in March 2024.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The EU AI Act took effect in March 2024.", + "failure": null, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "visibility": "private", + "warnings": [ + "w1" + ] + } + }, + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": "upstream_unavailable", + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "failed", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": null, + "index": 1, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 2, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "assessment", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": null, + "confidence": null, + "content_status": "available", + "created_at": null, + "depth": null, + "domain": null, + "entities": [], + "executive_summary": null, + "failure": { + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "hint": null, + "retryable": false + }, + "key_finding": null, + "language": null, + "lenz_score": null, + "modified_at": null, + "status": "failed", + "suggested_rewrite": null, + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "url": null, + "verdict": null, + "verification_id": null, + "verification_url": null, + "visibility": null, + "warnings": [] + } + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Paris is the capital of France.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 3, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 13 + }, + "failure": null, + "failures": [ + { + "claim": "Water boils at 100 C at sea level.", + "claim_index": 1, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "stage": "assessment" + } + ], + "issues": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "verified_claim": null }, { @@ -304,7 +608,8 @@ "view": "full" }, "exit_code": 2, - "render": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 true or mostly true, 1 failed · 1 of 2 deep-checked · 13 credits \ncharged\n\n[1/4] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\n[2/4] Water boils at 100 C at sea level.\n Quick check failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\n[3/4] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Deep check failed: The deep check failed.\n\n[4/4] Paris is the capital of France.\n True (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_issues": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 true or mostly true, 1 failed · 1 of 2 deep-checked · 13 credits \ncharged\n\n[1/4] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\n[3/4] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Deep check failed: research_empty\n\n[2/4] Water boils at 100 C at sea level.\n Assessment failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_json": null + "render": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 true or mostly true, 1 failed · 1 of 2 deep-checked · 13 credits \ncharged\n\n[1/4] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\n[2/4] Water boils at 100 C at sea level.\n Quick check failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\n[3/4] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Deep check failed: The deep check failed.\n\n[4/4] Paris is the capital of France.\n True (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 true or mostly true, 1 failed · 1 of 2 deep-checked · 13 credits \ncharged\n\n[1/4] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\n[3/4] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Deep check failed: research_empty\n\n[2/4] Water boils at 100 C at sea level.\n Assessment failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='incomplete', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=4, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=3, failed=1), verifications=ReviewVerificationCounts(planned=2, completed=1, failed=1), issues=2, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=13), poll_after_seconds=None, issues=[ReviewIssue(claim_index=0, claim='The EU AI Act took effect in March 2024.', verified_claim=None, verdict='False', confidence='high', source='verification', verification_id='68ca4aaf', verification_status='completed', verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding='Finding for The EU AI Act took effect in March 2024.', rationale=None, suggested_rewrite='Fixed: The EU AI Act took effect in March 2024.', failure=None, suggested_edits=None), ReviewIssue(claim_index=2, claim='The Eiffel Tower is in Berlin.', verified_claim=None, verdict='False', confidence='high', source='assessment', verification_id=None, verification_status='failed', verification_url=None, url=None, escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding=None, rationale=None, suggested_rewrite=None, failure=FailureBlock(failure_reason='research_empty', failure_class='insufficient_evidence', retryable=False, hint=None, docs_url='https://lenz.io/docs/errors#insufficient-evidence'), suggested_edits=None)], failures=[ReviewFailure(claim_index=1, claim='Water boils at 100 C at sea level.', stage='assessment', failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='A model provider was unavailable for this item. Retry it; nothing was charged.', docs_url='https://lenz.io/docs/errors#upstream-unavailable'))], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='False', confidence='high', source='verification', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='Mostly False', confidence='medium', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='planned'), verification=ReviewVerification(status='completed', content_status='available', verification_id='68ca4aaf', task_id='7cff18da2d979d6370e54a160be121ad', claim='The EU AI Act took effect in March 2024.', language='en', visibility='private', depth='standard', domain='', entities=[], verdict='False', confidence='high', lenz_score=2, key_finding='Finding for The EU AI Act took effect in March 2024.', executive_summary='Summary for The EU AI Act took effect in March 2024.', suggested_rewrite='Fixed: The EU AI Act took effect in March 2024.', warnings=['w1'], created_at='2026-10-01T09:14:00.123456+00:00', modified_at=None, verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', failure=None), suggested_edits=None), ReviewClaim(index=1, claim='Water boils at 100 C at sea level.', positions=None, result=None, assessment=ReviewAssessment(status='failed', verdict=None, confidence=None, rationale=None, dissent=None, verification_url=None, error_code='upstream_unavailable', identified_claims=[], hint=None, suggested_rewrite=None, failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='A model provider was unavailable for this item. Retry it; nothing was charged.', docs_url='https://lenz.io/docs/errors#upstream-unavailable')), escalation=None, verification=None, suggested_edits=None), ReviewClaim(index=2, claim='The Eiffel Tower is in Berlin.', positions=None, result=ReviewResult(verdict='False', confidence='high', source='assessment', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='False', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='planned'), verification=ReviewVerification(status='failed', content_status='available', verification_id=None, task_id='0b92b443eb69b9c71434fdc64f2ca8be', claim=None, language=None, visibility=None, depth=None, domain=None, entities=[], verdict=None, confidence=None, lenz_score=None, key_finding=None, executive_summary=None, suggested_rewrite=None, warnings=[], created_at=None, modified_at=None, verification_url=None, url=None, failure=FailureBlock(failure_reason='research_empty', failure_class='insufficient_evidence', retryable=False, hint=None, docs_url='https://lenz.io/docs/errors#insufficient-evidence')), suggested_edits=None), ReviewClaim(index=3, claim='Paris is the capital of France.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_completed_issues_view_issues.json b/tests/fixtures/parity/expected/review__get_completed_issues_view_issues.json index c0c2c56..ecbfeda 100644 --- a/tests/fixtures/parity/expected/review__get_completed_issues_view_issues.json +++ b/tests/fixtures/parity/expected/review__get_completed_issues_view_issues.json @@ -4,8 +4,8 @@ "citation_issues": [], "citations": [], "claims": [], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 13 }, @@ -41,11 +41,136 @@ "source": "verification", "suggested_edits": null, "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "verified_claim": null + }, + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 2, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "hint": null, + "retryable": false + }, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": null, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": "failed", + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "incomplete", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 3, + "failed": 1 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 4, + "input_truncated": false, + "issues": 2, + "verifications": { + "completed": 1, + "failed": 1, + "planned": 2 + } + }, + "view": "issues" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 13 + }, + "failure": null, + "failures": [ + { + "claim": "Water boils at 100 C at sea level.", + "claim_index": 1, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "stage": "assessment" + } + ], + "issues": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The EU AI Act took effect in March 2024.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The EU AI Act took effect in March 2024.", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "verified_claim": null }, { @@ -128,6 +253,7 @@ }, "exit_code": 2, "render": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 failed, 1 not checked · 1 of 2 deep-checked · 13 credits charged\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_issues": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 failed, 1 not checked · 1 of 2 deep-checked · 13 credits charged\n\n[1/4] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\n[3/4] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Deep check failed: research_empty\n\n[2/4] Water boils at 100 C at sea level.\n Assessment failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_json": null + "render_issues": "Review d6b2bd72: incomplete — 4 claims: 2 issues, 1 failed, 1 not checked · 1 of 2 deep-checked · 13 credits charged\n\n[1/4] The EU AI Act took effect in March 2024.\n False (high) · deep check\n Finding for The EU AI Act took effect in March 2024.\n Suggested rewrite: Fixed: The EU AI Act took effect in March 2024.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\n[3/4] The Eiffel Tower is in Berlin.\n False (high) · quick check\n Deep check failed: research_empty\n\n[2/4] Water boils at 100 C at sea level.\n Assessment failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='issues', status='completed', outcome='incomplete', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=4, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=3, failed=1), verifications=ReviewVerificationCounts(planned=2, completed=1, failed=1), issues=2, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=13), poll_after_seconds=None, issues=[ReviewIssue(claim_index=0, claim='The EU AI Act took effect in March 2024.', verified_claim=None, verdict='False', confidence='high', source='verification', verification_id='68ca4aaf', verification_status='completed', verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding='Finding for The EU AI Act took effect in March 2024.', rationale=None, suggested_rewrite='Fixed: The EU AI Act took effect in March 2024.', failure=None, suggested_edits=None), ReviewIssue(claim_index=2, claim='The Eiffel Tower is in Berlin.', verified_claim=None, verdict='False', confidence='high', source='assessment', verification_id=None, verification_status='failed', verification_url=None, url=None, escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding=None, rationale=None, suggested_rewrite=None, failure=FailureBlock(failure_reason='research_empty', failure_class='insufficient_evidence', retryable=False, hint=None, docs_url='https://lenz.io/docs/errors#insufficient-evidence'), suggested_edits=None)], failures=[ReviewFailure(claim_index=1, claim='Water boils at 100 C at sea level.', stage='assessment', failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='A model provider was unavailable for this item. Retry it; nothing was charged.', docs_url='https://lenz.io/docs/errors#upstream-unavailable'))], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_completed_positions.json b/tests/fixtures/parity/expected/review__get_completed_positions.json index f89f5be..b438323 100644 --- a/tests/fixtures/parity/expected/review__get_completed_positions.json +++ b/tests/fixtures/parity/expected/review__get_completed_positions.json @@ -77,8 +77,142 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": [ + { + "end": 40, + "start": 0, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": [ + { + "end": 89, + "start": 55, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -136,5 +270,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024. · at 0-40\n True (high) · quick check\n\n[2/2] Water boils at 100 C at sea level. · at 55-89\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=2, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=[Position(start=0, end=40, text='The EU AI Act took effect in March 2024.')], result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None), ReviewClaim(index=1, claim='Water boils at 100 C at sea level.', positions=[Position(start=55, end=89, text='Water boils at 100 C at sea level.')], result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_completed_recovered_claim.json b/tests/fixtures/parity/expected/review__get_completed_recovered_claim.json index dde95e1..ee17c63 100644 --- a/tests/fixtures/parity/expected/review__get_completed_recovered_claim.json +++ b/tests/fixtures/parity/expected/review__get_completed_recovered_claim.json @@ -35,8 +35,100 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Orbit Motors stock increased by 40% in 2022.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": [], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -94,5 +186,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] Orbit Motors stock increased by 40% in 2022.\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=1), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='Orbit Motors stock increased by 40% in 2022.', positions=[], result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_completed_with_untraced_claim.json b/tests/fixtures/parity/expected/review__get_completed_with_untraced_claim.json index cdb1fd6..a57ad21 100644 --- a/tests/fixtures/parity/expected/review__get_completed_with_untraced_claim.json +++ b/tests/fixtures/parity/expected/review__get_completed_with_untraced_claim.json @@ -77,8 +77,142 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": [ + { + "end": 40, + "start": 0, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": [ + { + "end": 84, + "start": 50, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -136,5 +270,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024. · at 0-40\n True (high) · quick check\n\n[2/2] Water boils at 100 C at sea level. · at 50-84\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=2, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=[Position(start=0, end=40, text='The EU AI Act took effect in March 2024.')], result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None), ReviewClaim(index=1, claim='Water boils at 100 C at sea level.', positions=[Position(start=50, end=84, text='Water boils at 100 C at sea level.')], result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_during_quick_check.json b/tests/fixtures/parity/expected/review__get_during_quick_check.json index efe850f..f321920 100644 --- a/tests/fixtures/parity/expected/review__get_during_quick_check.json +++ b/tests/fixtures/parity/expected/review__get_during_quick_check.json @@ -28,7 +28,87 @@ } ], "completed_at": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 10, + "review_id": "d6b2bd72", + "status": "assessing", + "summary": { + "assessments": { + "completed": 0, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "running", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": null, + "index": 0, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": null, + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -82,5 +162,6 @@ "exit_code": 2, "render": "Review d6b2bd72: assessing — 1 claim: 1 not checked · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n ? · quick check\n", "render_issues": "Review d6b2bd72: assessing — 1 claim: 1 not checked · 1 credit charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='assessing', outcome=None, created_at='2026-10-01T09:07:00.123456Z', completed_at=None, language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=0, failed=0), verifications=None, issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=1), poll_after_seconds=10, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=None, assessment=ReviewAssessment(status='running', verdict=None, confidence=None, rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=None, verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_failed_every_assessment_failed.json b/tests/fixtures/parity/expected/review__get_failed_every_assessment_failed.json index d9d5414..d7ffa8d 100644 --- a/tests/fixtures/parity/expected/review__get_failed_every_assessment_failed.json +++ b/tests/fixtures/parity/expected/review__get_failed_every_assessment_failed.json @@ -61,8 +61,157 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "assessment_failed", + "hint": "No claim could be assessed. Retry the review with a new Idempotency-Key; nothing was charged.", + "retryable": true + }, + "failures": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "stage": "assessment" + }, + { + "claim": "Water boils at 100 C at sea level.", + "claim_index": 1, + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "stage": "assessment" + } + ], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "incomplete", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "failed", + "summary": { + "assessments": { + "completed": 0, + "failed": 2 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": "upstream_unavailable", + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "failed", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": null, + "index": 0, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": null, + "dissent": null, + "error_code": "upstream_unavailable", + "failure": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "failure_class": "upstream_unavailable", + "failure_reason": "upstream_unavailable", + "hint": "A model provider was unavailable for this item. Retry it; nothing was charged.", + "retryable": true + }, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "failed", + "suggested_rewrite": null, + "verdict": null, + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": null, + "index": 1, + "positions": null, + "result": null, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -151,5 +300,6 @@ "exit_code": 2, "render": "Review d6b2bd72: incomplete — 2 claims: 2 failed · 0 credits charged\nFailed: No claim could be assessed. Retry the review with a new Idempotency-Key; nothing was charged.\n\n[1/2] The EU AI Act took effect in March 2024.\n Quick check failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\n[2/2] Water boils at 100 C at sea level.\n Quick check failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n", "render_issues": "Review d6b2bd72: incomplete — 2 claims: 2 failed · 0 credits charged\nFailed: No claim could be assessed. Retry the review with a new Idempotency-Key; nothing was charged.\n\n[1/2] The EU AI Act took effect in March 2024.\n Assessment failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n\n[2/2] Water boils at 100 C at sea level.\n Assessment failed: A model provider was unavailable for this item. Retry it; nothing was charged.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='failed', outcome='incomplete', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=0, failed=2), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=0), poll_after_seconds=None, issues=[], failures=[ReviewFailure(claim_index=0, claim='The EU AI Act took effect in March 2024.', stage='assessment', failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='A model provider was unavailable for this item. Retry it; nothing was charged.', docs_url='https://lenz.io/docs/errors#upstream-unavailable')), ReviewFailure(claim_index=1, claim='Water boils at 100 C at sea level.', stage='assessment', failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='A model provider was unavailable for this item. Retry it; nothing was charged.', docs_url='https://lenz.io/docs/errors#upstream-unavailable'))], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=FailureBlock(failure_reason='assessment_failed', failure_class='upstream_unavailable', retryable=True, hint='No claim could be assessed. Retry the review with a new Idempotency-Key; nothing was charged.', docs_url='https://lenz.io/docs/errors#upstream-unavailable'), claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=None, assessment=ReviewAssessment(status='failed', verdict=None, confidence=None, rationale=None, dissent=None, verification_url=None, error_code='upstream_unavailable', identified_claims=[], hint=None, suggested_rewrite=None, failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='A model provider was unavailable for this item. Retry it; nothing was charged.', docs_url='https://lenz.io/docs/errors#upstream-unavailable')), escalation=None, verification=None, suggested_edits=None), ReviewClaim(index=1, claim='Water boils at 100 C at sea level.', positions=None, result=None, assessment=ReviewAssessment(status='failed', verdict=None, confidence=None, rationale=None, dissent=None, verification_url=None, error_code='upstream_unavailable', identified_claims=[], hint=None, suggested_rewrite=None, failure=FailureBlock(failure_reason='upstream_unavailable', failure_class='upstream_unavailable', retryable=True, hint='A model provider was unavailable for this item. Retry it; nothing was charged.', docs_url='https://lenz.io/docs/errors#upstream-unavailable')), escalation=None, verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_failed_no_claim.json b/tests/fixtures/parity/expected/review__get_failed_no_claim.json index 8a2a3a1..831acdf 100644 --- a/tests/fixtures/parity/expected/review__get_failed_no_claim.json +++ b/tests/fixtures/parity/expected/review__get_failed_no_claim.json @@ -4,8 +4,68 @@ "citation_issues": [], "citations": [], "claims": [], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "no_claim", + "hint": "The text is a greeting, not a statement about the world. Send one factual claim, or run the text through /extract to enumerate its claims.", + "retryable": false + }, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": "unchecked", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "failed", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -62,5 +122,6 @@ "exit_code": 2, "render": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: The text is a greeting, not a statement about the world. Send one factual claim, or run the text through \n/extract to enumerate its claims.\n", "render_issues": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: The text is a greeting, not a statement about the world. Send one factual claim, or run the text through \n/extract to enumerate its claims.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='failed', outcome='unchecked', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=None, claim_limit=20, claim_limit_reached=None, input_truncated=False, assessments=None, verifications=None, issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=0), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=None, more_claim_locations=None, more_citations=None, failure=FailureBlock(failure_reason='no_claim', failure_class='invalid_input', retryable=False, hint='The text is a greeting, not a statement about the world. Send one factual claim, or run the text through /extract to enumerate its claims.', docs_url='https://lenz.io/docs/errors#invalid-input'), claims=[], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_failed_no_claim_untraced.json b/tests/fixtures/parity/expected/review__get_failed_no_claim_untraced.json index 435f4a6..c371358 100644 --- a/tests/fixtures/parity/expected/review__get_failed_no_claim_untraced.json +++ b/tests/fixtures/parity/expected/review__get_failed_no_claim_untraced.json @@ -4,8 +4,68 @@ "citation_issues": [], "citations": [], "claims": [], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "failure_class": "invalid_input", + "failure_reason": "no_claim", + "hint": "None of the claims found in the text could be traced back to it. Send one factual claim, or run the text through /extract to enumerate its claims.", + "retryable": false + }, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": "unchecked", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "failed", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -62,5 +122,6 @@ "exit_code": 2, "render": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: None of the claims found in the text could be traced back to it. Send one factual claim, or run the text through\n/extract to enumerate its claims.\n", "render_issues": "Review d6b2bd72: unchecked — no claims checked · 0 credits charged\nFailed: None of the claims found in the text could be traced back to it. Send one factual claim, or run the text through\n/extract to enumerate its claims.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='failed', outcome='unchecked', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=None, claim_limit=20, claim_limit_reached=None, input_truncated=False, assessments=None, verifications=None, issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=0), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=None, more_claim_locations=None, more_citations=None, failure=FailureBlock(failure_reason='no_claim', failure_class='invalid_input', retryable=False, hint='None of the claims found in the text could be traced back to it. Send one factual claim, or run the text through /extract to enumerate its claims.', docs_url='https://lenz.io/docs/errors#invalid-input'), claims=[], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_more_claims.json b/tests/fixtures/parity/expected/review__get_more_claims.json index e22d03e..aa3064b 100644 --- a/tests/fixtures/parity/expected/review__get_more_claims.json +++ b/tests/fixtures/parity/expected/review__get_more_claims.json @@ -77,8 +77,155 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "positions": [ + { + "end": 121, + "start": 91, + "text": "The Eiffel Tower is in Berlin." + } + ] + } + ], + "more_claims": [ + "The Eiffel Tower is in Berlin." + ], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 2, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 2, + "claim_limit_reached": true, + "claims_selected": 2, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": [ + { + "end": 40, + "start": 0, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": [ + { + "end": 84, + "start": 50, + "text": "Water boils at 100 C at sea level." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -149,5 +296,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024. · at 0-40\n True (high) · quick check\n\n[2/2] Water boils at 100 C at sea level. · at 50-84\n True (high) · quick check\n\n1 more claim was found but not checked.\n", "render_issues": "Review d6b2bd72: clean — 2 claims: 2 true or mostly true · 2 credits charged\n\nNo issues.\n\n1 more claim was found but not checked.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=2, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=2, claim_limit_reached=True, input_truncated=False, assessments=ReviewAssessmentCounts(completed=2, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=['The Eiffel Tower is in Berlin.'], more_claim_locations=[ClaimLocation(claim='The Eiffel Tower is in Berlin.', positions=[Position(start=91, end=121, text='The Eiffel Tower is in Berlin.')])], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=[Position(start=0, end=40, text='The EU AI Act took effect in March 2024.')], result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None), ReviewClaim(index=1, claim='Water boils at 100 C at sea level.', positions=[Position(start=50, end=84, text='Water boils at 100 C at sea level.')], result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json index 56e09af..71085d6 100644 --- a/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json @@ -50,11 +50,11 @@ "modified_at": "2026-10-02T00:03:00.123456+00:00", "status": "completed", "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "task_id": "7df4009bc27aab64ce5d5a01fbafe599", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "b4e2e99d", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "visibility": "private", "warnings": [ "w1" @@ -62,8 +62,8 @@ } } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 11 }, @@ -86,11 +86,154 @@ "source": "verification", "suggested_edits": null, "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 1, + "failed": 0, + "planned": 1 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "language": "en", + "lenz_score": 2, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "status": "completed", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "visibility": "private", + "warnings": [ + "w1" + ] + } + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 11 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "verified_claim": null } ], @@ -143,7 +286,8 @@ "view": "full" }, "exit_code": 1, - "render": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_issues": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_json": null + "render": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='issues_found', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=1, completed=1, failed=0), issues=1, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=11), poll_after_seconds=None, issues=[ReviewIssue(claim_index=0, claim='The Eiffel Tower is in Berlin.', verified_claim=None, verdict='False', confidence='high', source='verification', verification_id='68ca4aaf', verification_status='completed', verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding='Finding for The Eiffel Tower is in Berlin.', rationale=None, suggested_rewrite='Fixed: The Eiffel Tower is in Berlin.', failure=None, suggested_edits=None)], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The Eiffel Tower is in Berlin.', positions=None, result=ReviewResult(verdict='False', confidence='high', source='verification', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='False', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='planned'), verification=ReviewVerification(status='completed', content_status='available', verification_id='68ca4aaf', task_id='7cff18da2d979d6370e54a160be121ad', claim='The Eiffel Tower is in Berlin.', language='en', visibility='private', depth='standard', domain='', entities=[], verdict='False', confidence='high', lenz_score=2, key_finding='Finding for The Eiffel Tower is in Berlin.', executive_summary='Summary for The Eiffel Tower is in Berlin.', suggested_rewrite='Fixed: The Eiffel Tower is in Berlin.', warnings=['w1'], created_at='2026-10-01T23:55:00.123456+00:00', modified_at='2026-10-02T00:03:00.123456+00:00', verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', failure=None), suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_same_day_hours_apart.json index ac41e67..554926b 100644 --- a/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/expected/review__get_nested_verification_modified_at_same_day_hours_apart.json @@ -50,11 +50,11 @@ "modified_at": null, "status": "completed", "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "task_id": "7df4009bc27aab64ce5d5a01fbafe599", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "b4e2e99d", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "visibility": "private", "warnings": [ "w1" @@ -62,8 +62,8 @@ } } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 11 }, @@ -86,11 +86,154 @@ "source": "verification", "suggested_edits": null, "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "issues_found", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 1, + "failed": 0, + "planned": 1 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "visibility": "private", + "warnings": [ + "w1" + ] + } + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 11 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": null, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "verified_claim": null } ], @@ -143,7 +286,8 @@ "view": "full" }, "exit_code": 1, - "render": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_issues": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-b4e2e99d\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_json": null + "render": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: issues found — 1 claim: 1 issue · 1 of 1 deep-checked · 11 credits charged\n\n[1/1] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='issues_found', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=1, completed=1, failed=0), issues=1, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=11), poll_after_seconds=None, issues=[ReviewIssue(claim_index=0, claim='The Eiffel Tower is in Berlin.', verified_claim=None, verdict='False', confidence='high', source='verification', verification_id='68ca4aaf', verification_status='completed', verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding='Finding for The Eiffel Tower is in Berlin.', rationale=None, suggested_rewrite='Fixed: The Eiffel Tower is in Berlin.', failure=None, suggested_edits=None)], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The Eiffel Tower is in Berlin.', positions=None, result=ReviewResult(verdict='False', confidence='high', source='verification', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='False', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='planned'), verification=ReviewVerification(status='completed', content_status='available', verification_id='68ca4aaf', task_id='7cff18da2d979d6370e54a160be121ad', claim='The Eiffel Tower is in Berlin.', language='en', visibility='private', depth='standard', domain='', entities=[], verdict='False', confidence='high', lenz_score=2, key_finding='Finding for The Eiffel Tower is in Berlin.', executive_summary='Summary for The Eiffel Tower is in Berlin.', suggested_rewrite='Fixed: The Eiffel Tower is in Berlin.', warnings=['w1'], created_at='2026-10-01T08:00:00.123456+00:00', modified_at=None, verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', failure=None), suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_policy_resolved.json b/tests/fixtures/parity/expected/review__get_policy_resolved.json index d49a7f7..dc93371 100644 --- a/tests/fixtures/parity/expected/review__get_policy_resolved.json +++ b/tests/fixtures/parity/expected/review__get_policy_resolved.json @@ -35,8 +35,98 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "low", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 2, + "suggest_edits": false, + "verdicts": [ + "False" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -92,5 +182,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False'], confidence=['low'], max_assessments=20, max_verifications=2, depth='low', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=1), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_queued.json b/tests/fixtures/parity/expected/review__get_queued.json index 00606b0..45e6ec0 100644 --- a/tests/fixtures/parity/expected/review__get_queued.json +++ b/tests/fixtures/parity/expected/review__get_queued.json @@ -5,7 +5,61 @@ "citations": [], "claims": [], "completed_at": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 0 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": null, + "more_claim_locations": null, + "more_claims": null, + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 10, + "review_id": "d6b2bd72", + "status": "queued", + "summary": { + "assessments": null, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": null, + "claims_selected": null, + "input_truncated": false, + "issues": 0, + "verifications": null + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [], + "completed_at": null, + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -56,5 +110,6 @@ "exit_code": 2, "render": "Review d6b2bd72: queued — no claims checked · 0 credits charged\n", "render_issues": "Review d6b2bd72: queued — no claims checked · 0 credits charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='queued', outcome=None, created_at='2026-10-01T09:07:00.123456Z', completed_at=None, language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=None, claim_limit=20, claim_limit_reached=None, input_truncated=False, assessments=None, verifications=None, issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=0), poll_after_seconds=10, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=None, more_claim_locations=None, more_citations=None, failure=None, claims=[], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_suggested_edits.json b/tests/fixtures/parity/expected/review__get_suggested_edits.json index 9624e1d..5f8332a 100644 --- a/tests/fixtures/parity/expected/review__get_suggested_edits.json +++ b/tests/fixtures/parity/expected/review__get_suggested_edits.json @@ -55,7 +55,7 @@ "claim": "The Eiffel Tower is in Berlin.", "confidence": "high", "content_status": "available", - "created_at": "2026-10-01T09:35:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "depth": "standard", "domain": "", "entities": [], @@ -67,11 +67,11 @@ "modified_at": null, "status": "completed", "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "task_id": "9bca1e0819de60a750186e812dc58e2b", - "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "7c83247c", - "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "visibility": "private", "warnings": [ "w1" @@ -144,7 +144,7 @@ } ], "completed_at": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 12 }, @@ -178,11 +178,272 @@ "status": "completed" }, "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "7c83247c", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "verified_claim": null + }, + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 1, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": { + "edits": null, + "status": "pending" + }, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": true, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 15, + "review_id": "d6b2bd72", + "status": "verifying", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 2, + "verifications": { + "completed": 1, + "failed": 0, + "planned": 2 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The Eiffel Tower is in Berlin.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": [ + { + "end": 30, + "start": 0, + "text": "The Eiffel Tower is in Berlin." + } + ], + "result": { + "confidence": "high", + "is_issue": true, + "source": "verification", + "verdict": "False" + }, + "suggested_edits": { + "edits": [ + { + "end": 29, + "position": 0, + "replacement": "Paris", + "start": 23, + "text": "Berlin" + } + ], + "status": "completed" + }, + "verification": { + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "high", + "content_status": "available", + "created_at": "2026-10-01T09:14:00.123456+00:00", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "Summary for The Eiffel Tower is in Berlin.", + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "language": "en", + "lenz_score": 2, + "modified_at": null, + "status": "completed", + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "visibility": "private", + "warnings": [ + "w1" + ] + } + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 1, + "positions": [ + { + "end": 85, + "start": 45, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "confidence": "high", + "is_issue": true, + "source": "assessment", + "verdict": "False" + }, + "suggested_edits": { + "edits": null, + "status": "pending" + }, + "verification": { + "claim": null, + "confidence": null, + "content_status": "available", + "created_at": null, + "depth": null, + "domain": null, + "entities": [], + "executive_summary": null, + "failure": null, + "key_finding": null, + "language": null, + "lenz_score": null, + "modified_at": null, + "status": "processing", + "suggested_rewrite": null, + "task_id": null, + "url": null, + "verdict": null, + "verification_id": null, + "verification_url": null, + "visibility": null, + "warnings": [] + } + } + ], + "completed_at": null, + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 12 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": { + "edits": [ + { + "end": 29, + "position": 0, + "replacement": "Paris", + "start": 23, + "text": "Berlin" + } + ], + "status": "completed" + }, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "verified_claim": null }, { @@ -261,7 +522,8 @@ "view": "full" }, "exit_code": 2, - "render": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\n[1/2] The Eiffel Tower is in Berlin. · at 0-30\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-7c83247c\n\n[2/2] The EU AI Act took effect in March 2024. · at 45-85\n False (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_issues": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\n[1/2] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-7c83247c\n\n[2/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_json": null + "render": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\n[1/2] The Eiffel Tower is in Berlin. · at 0-30\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\n[2/2] The EU AI Act took effect in March 2024. · at 45-85\n False (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_issues": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\n[1/2] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\n[2/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='verifying', outcome=None, created_at='2026-10-01T09:07:00.123456Z', completed_at=None, language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=True), summary=ReviewSummary(claims_selected=2, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=2, failed=0), verifications=ReviewVerificationCounts(planned=2, completed=1, failed=0), issues=2, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=12), poll_after_seconds=15, issues=[ReviewIssue(claim_index=0, claim='The Eiffel Tower is in Berlin.', verified_claim=None, verdict='False', confidence='high', source='verification', verification_id='68ca4aaf', verification_status='completed', verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding='Finding for The Eiffel Tower is in Berlin.', rationale=None, suggested_rewrite='Fixed: The Eiffel Tower is in Berlin.', failure=None, suggested_edits=SuggestedEdits(status='completed', edits=[SuggestedEdit(position=0, start=23, end=29, text='Berlin', replacement='Paris')])), ReviewIssue(claim_index=1, claim='The EU AI Act took effect in March 2024.', verified_claim=None, verdict='False', confidence='high', source='assessment', verification_id=None, verification_status='processing', verification_url=None, url=None, escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding=None, rationale=None, suggested_rewrite=None, failure=None, suggested_edits=SuggestedEdits(status='pending', edits=None))], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The Eiffel Tower is in Berlin.', positions=[Position(start=0, end=30, text='The Eiffel Tower is in Berlin.')], result=ReviewResult(verdict='False', confidence='high', source='verification', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='False', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='planned'), verification=ReviewVerification(status='completed', content_status='available', verification_id='68ca4aaf', task_id='7cff18da2d979d6370e54a160be121ad', claim='The Eiffel Tower is in Berlin.', language='en', visibility='private', depth='standard', domain='', entities=[], verdict='False', confidence='high', lenz_score=2, key_finding='Finding for The Eiffel Tower is in Berlin.', executive_summary='Summary for The Eiffel Tower is in Berlin.', suggested_rewrite='Fixed: The Eiffel Tower is in Berlin.', warnings=['w1'], created_at='2026-10-01T09:14:00.123456+00:00', modified_at=None, verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', failure=None), suggested_edits=SuggestedEdits(status='completed', edits=[SuggestedEdit(position=0, start=23, end=29, text='Berlin', replacement='Paris')])), ReviewClaim(index=1, claim='The EU AI Act took effect in March 2024.', positions=[Position(start=45, end=85, text='The EU AI Act took effect in March 2024.')], result=ReviewResult(verdict='False', confidence='high', source='assessment', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='False', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='planned'), verification=ReviewVerification(status='processing', content_status='available', verification_id=None, task_id=None, claim=None, language=None, visibility=None, depth=None, domain=None, entities=[], verdict=None, confidence=None, lenz_score=None, key_finding=None, executive_summary=None, suggested_rewrite=None, warnings=[], created_at=None, modified_at=None, verification_url=None, url=None, failure=None), suggested_edits=SuggestedEdits(status='pending', edits=None))], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_suggested_edits_issues_view.json b/tests/fixtures/parity/expected/review__get_suggested_edits_issues_view.json index 2f8589c..ec30607 100644 --- a/tests/fixtures/parity/expected/review__get_suggested_edits_issues_view.json +++ b/tests/fixtures/parity/expected/review__get_suggested_edits_issues_view.json @@ -5,7 +5,7 @@ "citations": [], "claims": [], "completed_at": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 12 }, @@ -39,11 +39,131 @@ "status": "completed" }, "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "7c83247c", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "verified_claim": null + }, + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 1, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": { + "edits": null, + "status": "pending" + }, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": true, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 15, + "review_id": "d6b2bd72", + "status": "verifying", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 2, + "verifications": { + "completed": 1, + "failed": 0, + "planned": 2 + } + }, + "view": "issues" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "completed_at": null, + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 12 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The Eiffel Tower is in Berlin.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": "Finding for The Eiffel Tower is in Berlin.", + "rationale": null, + "source": "verification", + "suggested_edits": { + "edits": [ + { + "end": 29, + "position": 0, + "replacement": "Paris", + "start": 23, + "text": "Berlin" + } + ], + "status": "completed" + }, + "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", + "verdict": "False", + "verification_id": "68ca4aaf", + "verification_status": "completed", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "verified_claim": null }, { @@ -123,6 +243,7 @@ }, "exit_code": 2, "render": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_issues": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\n[1/2] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-7c83247c\n\n[2/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", - "render_json": null + "render_issues": "Review d6b2bd72: verifying — 2 claims: 2 issues · 1 of 2 deep-checked · 12 credits charged\n\n[1/2] The Eiffel Tower is in Berlin.\n False (high) · deep check\n Finding for The Eiffel Tower is in Berlin.\n Suggested rewrite: Fixed: The Eiffel Tower is in Berlin.\n https://lenz.io/c/the-earth-is-round-68ca4aaf\n\n[2/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n\nA suggested rewrite has not been verified itself: review it, or run it through `lenz verify`, before you use it.\n", + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='issues', status='verifying', outcome=None, created_at='2026-10-01T09:07:00.123456Z', completed_at=None, language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=True), summary=ReviewSummary(claims_selected=2, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=2, failed=0), verifications=ReviewVerificationCounts(planned=2, completed=1, failed=0), issues=2, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=12), poll_after_seconds=15, issues=[ReviewIssue(claim_index=0, claim='The Eiffel Tower is in Berlin.', verified_claim=None, verdict='False', confidence='high', source='verification', verification_id='68ca4aaf', verification_status='completed', verification_url='https://lenz.io/api/v1/verifications/68ca4aaf', url='https://lenz.io/c/the-earth-is-round-68ca4aaf', escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding='Finding for The Eiffel Tower is in Berlin.', rationale=None, suggested_rewrite='Fixed: The Eiffel Tower is in Berlin.', failure=None, suggested_edits=SuggestedEdits(status='completed', edits=[SuggestedEdit(position=0, start=23, end=29, text='Berlin', replacement='Paris')])), ReviewIssue(claim_index=1, claim='The EU AI Act took effect in March 2024.', verified_claim=None, verdict='False', confidence='high', source='assessment', verification_id=None, verification_status='processing', verification_url=None, url=None, escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding=None, rationale=None, suggested_rewrite=None, failure=None, suggested_edits=SuggestedEdits(status='pending', edits=None))], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_url_review.json b/tests/fixtures/parity/expected/review__get_url_review.json index ea99aa8..8153a7d 100644 --- a/tests/fixtures/parity/expected/review__get_url_review.json +++ b/tests/fixtures/parity/expected/review__get_url_review.json @@ -41,8 +41,106 @@ "verification": null } ], - "completed_at": "2026-10-01T09:21:00.123456Z", - "created_at": "2026-10-01T09:14:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 1 + }, + "failure": null, + "failures": [], + "issues": [], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": "clean", + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": null, + "review_id": "d6b2bd72", + "status": "completed", + "summary": { + "assessments": { + "completed": 1, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 1, + "input_truncated": false, + "issues": 0, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 0 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 0, + "positions": [ + { + "end": null, + "start": null, + "text": "The EU AI Act took effect in March 2024." + } + ], + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -100,5 +198,6 @@ "exit_code": 0, "render": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\n[1/1] The EU AI Act took effect in March 2024.\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: clean — 1 claim: 1 true or mostly true · 1 credit charged\n\nNo issues.\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='completed', outcome='clean', created_at='2026-10-01T09:07:00.123456Z', completed_at='2026-10-01T10:07:00.123456Z', language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=1, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=1, failed=0), verifications=ReviewVerificationCounts(planned=0, completed=0, failed=0), issues=0, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=1), poll_after_seconds=None, issues=[], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=[Position(start=None, end=None, text='The EU AI Act took effect in March 2024.')], result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__get_verifying.json b/tests/fixtures/parity/expected/review__get_verifying.json index 0b901c0..63b031e 100644 --- a/tests/fixtures/parity/expected/review__get_verifying.json +++ b/tests/fixtures/parity/expected/review__get_verifying.json @@ -91,7 +91,178 @@ } ], "completed_at": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "credits": { + "charged": 2 + }, + "failure": null, + "failures": [], + "issues": [ + { + "claim": "The EU AI Act took effect in March 2024.", + "claim_index": 0, + "confidence": "high", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "failure": null, + "key_finding": null, + "rationale": null, + "source": "assessment", + "suggested_edits": null, + "suggested_rewrite": null, + "url": null, + "verdict": "False", + "verification_id": null, + "verification_status": "processing", + "verification_url": null, + "verified_claim": null + } + ], + "language": "en", + "more_citations": [], + "more_claim_locations": [], + "more_claims": [], + "outcome": null, + "policy": { + "confidence": [ + "low" + ], + "depth": "standard", + "max_assessments": 20, + "max_citations": 0, + "max_verifications": 5, + "suggest_edits": false, + "verdicts": [ + "False", + "Mostly False", + "Mixed" + ] + }, + "poll_after_seconds": 15, + "review_id": "d6b2bd72", + "status": "verifying", + "summary": { + "assessments": { + "completed": 2, + "failed": 0 + }, + "citation_checks": null, + "citation_issues": 0, + "citation_limit": null, + "citation_limit_reached": null, + "citations_found": null, + "citations_selected": null, + "citations_skipped": null, + "claim_limit": 20, + "claim_limit_reached": false, + "claims_selected": 2, + "input_truncated": false, + "issues": 1, + "verifications": { + "completed": 0, + "failed": 0, + "planned": 1 + } + }, + "view": "full" + }, + "dump_unset": { + "citation_failures": [], + "citation_issues": [], + "citations": [], + "claims": [ + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "False", + "verification_url": null + }, + "claim": "The EU AI Act took effect in March 2024.", + "escalation": { + "disposition": "planned", + "matched_rules": [ + "verdict" + ] + }, + "index": 0, + "positions": null, + "result": { + "confidence": "high", + "is_issue": true, + "source": "assessment", + "verdict": "False" + }, + "suggested_edits": null, + "verification": { + "claim": null, + "confidence": null, + "content_status": "available", + "created_at": null, + "depth": null, + "domain": null, + "entities": [], + "executive_summary": null, + "failure": null, + "key_finding": null, + "language": null, + "lenz_score": null, + "modified_at": null, + "status": "processing", + "suggested_rewrite": null, + "task_id": null, + "url": null, + "verdict": null, + "verification_id": null, + "verification_url": null, + "visibility": null, + "warnings": [] + } + }, + { + "assessment": { + "confidence": "high", + "dissent": null, + "error_code": null, + "failure": null, + "hint": null, + "identified_claims": [], + "rationale": null, + "status": "completed", + "suggested_rewrite": null, + "verdict": "True", + "verification_url": null + }, + "claim": "Water boils at 100 C at sea level.", + "escalation": { + "disposition": "not_selected", + "matched_rules": [] + }, + "index": 1, + "positions": null, + "result": { + "confidence": "high", + "is_issue": false, + "source": "assessment", + "verdict": "True" + }, + "suggested_edits": null, + "verification": null + } + ], + "completed_at": null, + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -173,5 +344,6 @@ "exit_code": 2, "render": "Review d6b2bd72: verifying — 2 claims: 1 issue, 1 true or mostly true · 0 of 1 deep-checked · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n\n[2/2] Water boils at 100 C at sea level.\n True (high) · quick check\n", "render_issues": "Review d6b2bd72: verifying — 2 claims: 1 issue, 1 true or mostly true · 0 of 1 deep-checked · 2 credits charged\n\n[1/2] The EU AI Act took effect in March 2024.\n False (high) · quick check\n", - "render_json": null + "render_json": null, + "repr": "ReviewFull(review_id='d6b2bd72', view='full', status='verifying', outcome=None, created_at='2026-10-01T09:07:00.123456Z', completed_at=None, language='en', policy=EscalationPolicy(verdicts=['False', 'Mostly False', 'Mixed'], confidence=['low'], max_assessments=20, max_verifications=5, depth='standard', max_citations=0, suggest_edits=False), summary=ReviewSummary(claims_selected=2, claim_limit=20, claim_limit_reached=False, input_truncated=False, assessments=ReviewAssessmentCounts(completed=2, failed=0), verifications=ReviewVerificationCounts(planned=1, completed=0, failed=0), issues=1, citations_found=None, citations_selected=None, citation_limit=None, citation_limit_reached=None, citation_checks=None, citation_issues=0, citations_skipped=None), credits=ReviewCredits(charged=2), poll_after_seconds=15, issues=[ReviewIssue(claim_index=0, claim='The EU AI Act took effect in March 2024.', verified_claim=None, verdict='False', confidence='high', source='assessment', verification_id=None, verification_status='processing', verification_url=None, url=None, escalation=Escalation(matched_rules=['verdict'], disposition='planned'), key_finding=None, rationale=None, suggested_rewrite=None, failure=None, suggested_edits=None)], failures=[], citation_issues=[], citation_failures=[], more_claims=[], more_claim_locations=[], more_citations=[], failure=None, claims=[ReviewClaim(index=0, claim='The EU AI Act took effect in March 2024.', positions=None, result=ReviewResult(verdict='False', confidence='high', source='assessment', is_issue=True), assessment=ReviewAssessment(status='completed', verdict='False', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=['verdict'], disposition='planned'), verification=ReviewVerification(status='processing', content_status='available', verification_id=None, task_id=None, claim=None, language=None, visibility=None, depth=None, domain=None, entities=[], verdict=None, confidence=None, lenz_score=None, key_finding=None, executive_summary=None, suggested_rewrite=None, warnings=[], created_at=None, modified_at=None, verification_url=None, url=None, failure=None), suggested_edits=None), ReviewClaim(index=1, claim='Water boils at 100 C at sea level.', positions=None, result=ReviewResult(verdict='True', confidence='high', source='assessment', is_issue=False), assessment=ReviewAssessment(status='completed', verdict='True', confidence='high', rationale=None, dissent=None, verification_url=None, error_code=None, identified_claims=[], hint=None, suggested_rewrite=None, failure=None), escalation=Escalation(matched_rules=[], disposition='not_selected'), verification=None, suggested_edits=None)], citations=[])" } diff --git a/tests/fixtures/parity/expected/review__idempotent_replay_202.json b/tests/fixtures/parity/expected/review__idempotent_replay_202.json index 17e07a5..615c995 100644 --- a/tests/fixtures/parity/expected/review__idempotent_replay_202.json +++ b/tests/fixtures/parity/expected/review__idempotent_replay_202.json @@ -3,5 +3,10 @@ "review_id": "d6b2bd72", "status": "queued" }, - "render_json": null + "dump_unset": { + "review_id": "d6b2bd72", + "status": "queued" + }, + "render_json": null, + "repr": "ReviewStarted(review_id='d6b2bd72', status='queued')" } diff --git a/tests/fixtures/parity/expected/review__receipt_202.json b/tests/fixtures/parity/expected/review__receipt_202.json index 17e07a5..615c995 100644 --- a/tests/fixtures/parity/expected/review__receipt_202.json +++ b/tests/fixtures/parity/expected/review__receipt_202.json @@ -3,5 +3,10 @@ "review_id": "d6b2bd72", "status": "queued" }, - "render_json": null + "dump_unset": { + "review_id": "d6b2bd72", + "status": "queued" + }, + "render_json": null, + "repr": "ReviewStarted(review_id='d6b2bd72', status='queued')" } diff --git a/tests/fixtures/parity/expected/review__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/expected/review__receipt_202_empty_webhook_url.json index 17e07a5..615c995 100644 --- a/tests/fixtures/parity/expected/review__receipt_202_empty_webhook_url.json +++ b/tests/fixtures/parity/expected/review__receipt_202_empty_webhook_url.json @@ -3,5 +3,10 @@ "review_id": "d6b2bd72", "status": "queued" }, - "render_json": null + "dump_unset": { + "review_id": "d6b2bd72", + "status": "queued" + }, + "render_json": null, + "repr": "ReviewStarted(review_id='d6b2bd72', status='queued')" } diff --git a/tests/fixtures/parity/expected/review__receipt_202_webhook_url.json b/tests/fixtures/parity/expected/review__receipt_202_webhook_url.json index 17e07a5..615c995 100644 --- a/tests/fixtures/parity/expected/review__receipt_202_webhook_url.json +++ b/tests/fixtures/parity/expected/review__receipt_202_webhook_url.json @@ -3,5 +3,10 @@ "review_id": "d6b2bd72", "status": "queued" }, - "render_json": null + "dump_unset": { + "review_id": "d6b2bd72", + "status": "queued" + }, + "render_json": null, + "repr": "ReviewStarted(review_id='d6b2bd72', status='queued')" } diff --git a/tests/fixtures/parity/expected/review__replay_later_202.json b/tests/fixtures/parity/expected/review__replay_later_202.json index 17e07a5..615c995 100644 --- a/tests/fixtures/parity/expected/review__replay_later_202.json +++ b/tests/fixtures/parity/expected/review__replay_later_202.json @@ -3,5 +3,10 @@ "review_id": "d6b2bd72", "status": "queued" }, - "render_json": null + "dump_unset": { + "review_id": "d6b2bd72", + "status": "queued" + }, + "render_json": null, + "repr": "ReviewStarted(review_id='d6b2bd72', status='queued')" } diff --git a/tests/fixtures/parity/expected/verify__batch_202.json b/tests/fixtures/parity/expected/verify__batch_202.json index d044b7c..1f9894c 100644 --- a/tests/fixtures/parity/expected/verify__batch_202.json +++ b/tests/fixtures/parity/expected/verify__batch_202.json @@ -4,13 +4,27 @@ "items": [ { "claim_text": "The Earth is round.", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + { + "claim_text": "Water boils at 100C at sea level.", "task_id": "0b92b443eb69b9c71434fdc64f2ca8be" + } + ] + }, + "dump_unset": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "claim_text": "The Earth is round.", + "task_id": "7cff18da2d979d6370e54a160be121ad" }, { "claim_text": "Water boils at 100C at sea level.", - "task_id": "13610f0b64b63e006dc66364e0e82c85" + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be" } ] }, - "render_json": null + "render_json": null, + "repr": "BatchAccepted(batch_id='7ea9cdbd4064e3cf', items=[TaskAccepted(task_id='7cff18da2d979d6370e54a160be121ad', claim_text='The Earth is round.'), TaskAccepted(task_id='0b92b443eb69b9c71434fdc64f2ca8be', claim_text='Water boils at 100C at sea level.')])" } diff --git a/tests/fixtures/parity/expected/verify__batch_no_credits_402.json b/tests/fixtures/parity/expected/verify__batch_no_credits_402.json index 806620a..52d04da 100644 --- a/tests/fixtures/parity/expected/verify__batch_no_credits_402.json +++ b/tests/fixtures/parity/expected/verify__batch_no_credits_402.json @@ -20,7 +20,7 @@ "remaining": 0, "request_id": "", "requested": 1, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "status_code": 402, "type": "LenzQuotaExceededError", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" diff --git a/tests/fixtures/parity/expected/verify__batch_partial_202.json b/tests/fixtures/parity/expected/verify__batch_partial_202.json index 96fb74b..8a4a0ba 100644 --- a/tests/fixtures/parity/expected/verify__batch_partial_202.json +++ b/tests/fixtures/parity/expected/verify__batch_partial_202.json @@ -4,10 +4,21 @@ "items": [ { "claim_text": "First claim.", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be" + "task_id": "7cff18da2d979d6370e54a160be121ad" } ], "partial": true }, - "render_json": null + "dump_unset": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "claim_text": "First claim.", + "task_id": "7cff18da2d979d6370e54a160be121ad" + } + ], + "partial": true + }, + "render_json": null, + "repr": "BatchAccepted(batch_id='7ea9cdbd4064e3cf', items=[TaskAccepted(task_id='7cff18da2d979d6370e54a160be121ad', claim_text='First claim.')], partial=True)" } diff --git a/tests/fixtures/parity/expected/verify__delete_200.json b/tests/fixtures/parity/expected/verify__delete_200.json new file mode 100644 index 0000000..a75769b --- /dev/null +++ b/tests/fixtures/parity/expected/verify__delete_200.json @@ -0,0 +1,12 @@ +{ + "dump": { + "claim_text": "", + "ok": true, + "task_id": "" + }, + "dump_unset": { + "ok": true + }, + "render_json": null, + "repr": "TaskAccepted(task_id='', claim_text='', ok=True)" +} diff --git a/tests/fixtures/parity/expected/verify__delete_404.json b/tests/fixtures/parity/expected/verify__delete_404.json new file mode 100644 index 0000000..41573fe --- /dev/null +++ b/tests/fixtures/parity/expected/verify__delete_404.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__delete_not_yours_404.json b/tests/fixtures/parity/expected/verify__delete_not_yours_404.json new file mode 100644 index 0000000..41573fe --- /dev/null +++ b/tests/fixtures/parity/expected/verify__delete_not_yours_404.json @@ -0,0 +1,21 @@ +{ + "error": { + "cause": "Not found.", + "code": "", + "doc_url": "https://lenz.io/docs/errors", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "friendly_text": "Not found.\n Fix: Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "payload_json": { + "error": { + "code": "api_error", + "fix": "Retry; if the error persists, file an issue with the Request ID.", + "message": "Not found.", + "status": 404 + } + }, + "request_id": "", + "status_code": 404, + "type": "LenzError" + } +} diff --git a/tests/fixtures/parity/expected/verify__idempotency_key_replay.json b/tests/fixtures/parity/expected/verify__idempotency_key_replay.json index 4aa7f3a..74a0269 100644 --- a/tests/fixtures/parity/expected/verify__idempotency_key_replay.json +++ b/tests/fixtures/parity/expected/verify__idempotency_key_replay.json @@ -1,9 +1,15 @@ { "dump": { - "chain_id": "78ac4e9f234ea3bd", + "chain_id": "99a0a9ca89e1e72c", "claim_text": "", "status": "queued", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render_json": null + "dump_unset": { + "chain_id": "99a0a9ca89e1e72c", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null, + "repr": "TaskAccepted(task_id='7cff18da2d979d6370e54a160be121ad', claim_text='', status='queued', chain_id='99a0a9ca89e1e72c')" } diff --git a/tests/fixtures/parity/expected/verify__implicit_dedup_200.json b/tests/fixtures/parity/expected/verify__implicit_dedup_200.json index 77b6440..a7ae9ac 100644 --- a/tests/fixtures/parity/expected/verify__implicit_dedup_200.json +++ b/tests/fixtures/parity/expected/verify__implicit_dedup_200.json @@ -4,5 +4,10 @@ "status": "queued", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render_json": null + "dump_unset": { + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null, + "repr": "TaskAccepted(task_id='7cff18da2d979d6370e54a160be121ad', claim_text='', status='queued')" } diff --git a/tests/fixtures/parity/expected/verify__implicit_repeat_replay.json b/tests/fixtures/parity/expected/verify__implicit_repeat_replay.json index 4aa7f3a..74a0269 100644 --- a/tests/fixtures/parity/expected/verify__implicit_repeat_replay.json +++ b/tests/fixtures/parity/expected/verify__implicit_repeat_replay.json @@ -1,9 +1,15 @@ { "dump": { - "chain_id": "78ac4e9f234ea3bd", + "chain_id": "99a0a9ca89e1e72c", "claim_text": "", "status": "queued", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render_json": null + "dump_unset": { + "chain_id": "99a0a9ca89e1e72c", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null, + "repr": "TaskAccepted(task_id='7cff18da2d979d6370e54a160be121ad', claim_text='', status='queued', chain_id='99a0a9ca89e1e72c')" } diff --git a/tests/fixtures/parity/expected/verify__list_200.json b/tests/fixtures/parity/expected/verify__list_200.json index 9b7f3a5..ce1a3f5 100644 --- a/tests/fixtures/parity/expected/verify__list_200.json +++ b/tests/fixtures/parity/expected/verify__list_200.json @@ -1,6 +1,21 @@ { "dump": { "items": [ + { + "claim": "The Earth is round.", + "confidence": "high", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + }, { "claim": "The Earth is round.", "confidence": "high", @@ -14,12 +29,34 @@ "modified_at": null, "suggested_rewrite": null, "verdict": "True", + "verification_id": "4d44dfaf" + } + ], + "page": 1, + "page_size": 20, + "total": 2 + }, + "dump_unset": { + "items": [ + { + "claim": "The Earth is round.", + "confidence": "high", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", "verification_id": "68ca4aaf" }, { "claim": "The Earth is round.", "confidence": "high", - "created_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "domain": "Science", "entities": [], "executive_summary": "The claim is verified.", @@ -29,12 +66,13 @@ "modified_at": null, "suggested_rewrite": null, "verdict": "True", - "verification_id": "7c83247c" + "verification_id": "4d44dfaf" } ], "page": 1, "page_size": 20, "total": 2 }, - "render_json": null + "render_json": null, + "repr": "VerificationList(items=[VerificationListItem(verification_id='68ca4aaf', claim='The Earth is round.', domain='Science', entities=[], verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en'), VerificationListItem(verification_id='4d44dfaf', claim='The Earth is round.', domain='Science', entities=[], verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T09:14:00.123456+00:00', modified_at=None, language='en')], total=2, page=1, page_size=20)" } diff --git a/tests/fixtures/parity/expected/verify__list_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/verify__list_200_modified_at_crosses_midnight_by_minutes.json index 8550130..0483d52 100644 --- a/tests/fixtures/parity/expected/verify__list_200_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/expected/verify__list_200_modified_at_crosses_midnight_by_minutes.json @@ -21,5 +21,28 @@ "page_size": 20, "total": 1 }, - "render_json": null + "dump_unset": { + "items": [ + { + "claim": "The Earth is round.", + "confidence": "high", + "created_at": "2026-10-01T23:55:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + } + ], + "page": 1, + "page_size": 20, + "total": 1 + }, + "render_json": null, + "repr": "VerificationList(items=[VerificationListItem(verification_id='68ca4aaf', claim='The Earth is round.', domain='Science', entities=[], verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T23:55:00.123456+00:00', modified_at='2026-10-02T00:03:00.123456+00:00', language='en')], total=1, page=1, page_size=20)" } diff --git a/tests/fixtures/parity/expected/verify__list_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/verify__list_200_modified_at_same_day_hours_apart.json index b333318..43c5712 100644 --- a/tests/fixtures/parity/expected/verify__list_200_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/expected/verify__list_200_modified_at_same_day_hours_apart.json @@ -21,5 +21,28 @@ "page_size": 20, "total": 1 }, - "render_json": null + "dump_unset": { + "items": [ + { + "claim": "The Earth is round.", + "confidence": "high", + "created_at": "2026-10-01T08:00:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + } + ], + "page": 1, + "page_size": 20, + "total": 1 + }, + "render_json": null, + "repr": "VerificationList(items=[VerificationListItem(verification_id='68ca4aaf', claim='The Earth is round.', domain='Science', entities=[], verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T08:00:00.123456+00:00', modified_at=None, language='en')], total=1, page=1, page_size=20)" } diff --git a/tests/fixtures/parity/expected/verify__list_clamped_200.json b/tests/fixtures/parity/expected/verify__list_clamped_200.json index b48e6be..5f47a1d 100644 --- a/tests/fixtures/parity/expected/verify__list_clamped_200.json +++ b/tests/fixtures/parity/expected/verify__list_clamped_200.json @@ -5,5 +5,12 @@ "page_size": 100, "total": 0 }, - "render_json": null + "dump_unset": { + "items": [], + "page": 1, + "page_size": 100, + "total": 0 + }, + "render_json": null, + "repr": "VerificationList(items=[], total=0, page=1, page_size=100)" } diff --git a/tests/fixtures/parity/expected/verify__list_empty_200.json b/tests/fixtures/parity/expected/verify__list_empty_200.json index d628806..a0747d2 100644 --- a/tests/fixtures/parity/expected/verify__list_empty_200.json +++ b/tests/fixtures/parity/expected/verify__list_empty_200.json @@ -5,5 +5,12 @@ "page_size": 20, "total": 0 }, - "render_json": null + "dump_unset": { + "items": [], + "page": 1, + "page_size": 20, + "total": 0 + }, + "render_json": null, + "repr": "VerificationList(items=[], total=0, page=1, page_size=20)" } diff --git a/tests/fixtures/parity/expected/verify__list_page2_200.json b/tests/fixtures/parity/expected/verify__list_page2_200.json index c5aab9a..e2682ef 100644 --- a/tests/fixtures/parity/expected/verify__list_page2_200.json +++ b/tests/fixtures/parity/expected/verify__list_page2_200.json @@ -4,7 +4,7 @@ { "claim": "The Earth is round.", "confidence": "high", - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "domain": "Science", "entities": [], "executive_summary": "The claim is verified.", @@ -21,5 +21,28 @@ "page_size": 2, "total": 3 }, - "render_json": null + "dump_unset": { + "items": [ + { + "claim": "The Earth is round.", + "confidence": "high", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf" + } + ], + "page": 2, + "page_size": 2, + "total": 3 + }, + "render_json": null, + "repr": "VerificationList(items=[VerificationListItem(verification_id='68ca4aaf', claim='The Earth is round.', domain='Science', entities=[], verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', suggested_rewrite=None, created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en')], total=3, page=2, page_size=2)" } diff --git a/tests/fixtures/parity/expected/verify__no_credits_402.json b/tests/fixtures/parity/expected/verify__no_credits_402.json index f3a12a3..f16364a 100644 --- a/tests/fixtures/parity/expected/verify__no_credits_402.json +++ b/tests/fixtures/parity/expected/verify__no_credits_402.json @@ -20,7 +20,7 @@ "remaining": 0, "request_id": "", "requested": null, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "status_code": 402, "type": "LenzQuotaExceededError", "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57" diff --git a/tests/fixtures/parity/expected/verify__replay_later_202.json b/tests/fixtures/parity/expected/verify__replay_later_202.json index 4aa7f3a..74a0269 100644 --- a/tests/fixtures/parity/expected/verify__replay_later_202.json +++ b/tests/fixtures/parity/expected/verify__replay_later_202.json @@ -1,9 +1,15 @@ { "dump": { - "chain_id": "78ac4e9f234ea3bd", + "chain_id": "99a0a9ca89e1e72c", "claim_text": "", "status": "queued", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render_json": null + "dump_unset": { + "chain_id": "99a0a9ca89e1e72c", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null, + "repr": "TaskAccepted(task_id='7cff18da2d979d6370e54a160be121ad', claim_text='', status='queued', chain_id='99a0a9ca89e1e72c')" } diff --git a/tests/fixtures/parity/expected/verify__select_202.json b/tests/fixtures/parity/expected/verify__select_202.json index d044b7c..1f9894c 100644 --- a/tests/fixtures/parity/expected/verify__select_202.json +++ b/tests/fixtures/parity/expected/verify__select_202.json @@ -4,13 +4,27 @@ "items": [ { "claim_text": "The Earth is round.", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + { + "claim_text": "Water boils at 100C at sea level.", "task_id": "0b92b443eb69b9c71434fdc64f2ca8be" + } + ] + }, + "dump_unset": { + "batch_id": "7ea9cdbd4064e3cf", + "items": [ + { + "claim_text": "The Earth is round.", + "task_id": "7cff18da2d979d6370e54a160be121ad" }, { "claim_text": "Water boils at 100C at sea level.", - "task_id": "13610f0b64b63e006dc66364e0e82c85" + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be" } ] }, - "render_json": null + "render_json": null, + "repr": "BatchAccepted(batch_id='7ea9cdbd4064e3cf', items=[TaskAccepted(task_id='7cff18da2d979d6370e54a160be121ad', claim_text='The Earth is round.'), TaskAccepted(task_id='0b92b443eb69b9c71434fdc64f2ca8be', claim_text='Water boils at 100C at sea level.')])" } diff --git a/tests/fixtures/parity/expected/verify__status_cancelled_after_a_while.json b/tests/fixtures/parity/expected/verify__status_cancelled_after_a_while.json index 0c51d3c..820dfc6 100644 --- a/tests/fixtures/parity/expected/verify__status_cancelled_after_a_while.json +++ b/tests/fixtures/parity/expected/verify__status_cancelled_after_a_while.json @@ -22,8 +22,18 @@ "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "docs_url": "https://lenz.io/docs/errors#cancelled", + "error": "Cancelled.", + "failure_class": "cancelled", + "failure_reason": "cancelled", + "retryable": false, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "failed — Cancelled.\n", "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Cancelled.\",\n \"failure_reason\": \"cancelled\",\n \"failure_detail\": \"\",\n \"failure_class\": \"cancelled\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#cancelled\"\n}\n", + "repr": "TaskStatus(status='failed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[], candidates=[], similar_claims=[], error='Cancelled.', failure_reason='cancelled', failure_detail='', failure_class='cancelled', retryable=False, docs_url='https://lenz.io/docs/errors#cancelled')", "wait": { "cause": "Cancelled.", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_completed.json b/tests/fixtures/parity/expected/verify__status_completed.json index 4455d97..9f88760 100644 --- a/tests/fixtures/parity/expected/verify__status_completed.json +++ b/tests/fixtures/parity/expected/verify__status_completed.json @@ -64,7 +64,7 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -97,7 +97,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" @@ -108,9 +108,101 @@ "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", - "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:21:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", - "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "dump_unset": { + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 68ca4aaf\nfull report: lenz show 68ca4aaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "repr": "TaskStatus(status='completed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1')), claims=[], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "returned": { "audit": { @@ -160,7 +252,7 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -193,7 +285,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" diff --git a/tests/fixtures/parity/expected/verify__status_completed_after_a_while.json b/tests/fixtures/parity/expected/verify__status_completed_after_a_while.json index 4455d97..9f88760 100644 --- a/tests/fixtures/parity/expected/verify__status_completed_after_a_while.json +++ b/tests/fixtures/parity/expected/verify__status_completed_after_a_while.json @@ -64,7 +64,7 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -97,7 +97,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" @@ -108,9 +108,101 @@ "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", - "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:21:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", - "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "dump_unset": { + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 68ca4aaf\nfull report: lenz show 68ca4aaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "repr": "TaskStatus(status='completed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1')), claims=[], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "returned": { "audit": { @@ -160,7 +252,7 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -193,7 +285,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" diff --git a/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json index 3b77489..fd6df30 100644 --- a/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json @@ -97,7 +97,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" @@ -108,9 +108,101 @@ "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", - "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", - "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "dump_unset": { + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 68ca4aaf\nfull report: lenz show 68ca4aaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "repr": "TaskStatus(status='completed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T23:55:00.123456+00:00', modified_at='2026-10-02T00:03:00.123456+00:00', language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1')), claims=[], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "returned": { "audit": { @@ -193,7 +285,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" diff --git a/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json index 29f1593..b935bd9 100644 --- a/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/expected/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json @@ -97,7 +97,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" @@ -108,9 +108,101 @@ "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", - "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T08:00:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", - "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "dump_unset": { + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 68ca4aaf\nfull report: lenz show 68ca4aaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T08:00:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "repr": "TaskStatus(status='completed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T08:00:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1')), claims=[], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "returned": { "audit": { @@ -193,7 +285,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" diff --git a/tests/fixtures/parity/expected/verify__status_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/verify__status_completed_modified_at_crosses_midnight_by_minutes.json index 3b77489..fd6df30 100644 --- a/tests/fixtures/parity/expected/verify__status_completed_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/expected/verify__status_completed_modified_at_crosses_midnight_by_minutes.json @@ -97,7 +97,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" @@ -108,9 +108,101 @@ "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", - "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", - "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "dump_unset": { + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 68ca4aaf\nfull report: lenz show 68ca4aaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "repr": "TaskStatus(status='completed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T23:55:00.123456+00:00', modified_at='2026-10-02T00:03:00.123456+00:00', language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1')), claims=[], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "returned": { "audit": { @@ -193,7 +285,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" diff --git a/tests/fixtures/parity/expected/verify__status_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/verify__status_completed_modified_at_same_day_hours_apart.json index 29f1593..b935bd9 100644 --- a/tests/fixtures/parity/expected/verify__status_completed_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/expected/verify__status_completed_modified_at_same_day_hours_apart.json @@ -97,7 +97,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" @@ -108,9 +108,101 @@ "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", - "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T08:00:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", - "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "dump_unset": { + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 68ca4aaf\nfull report: lenz show 68ca4aaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T08:00:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "repr": "TaskStatus(status='completed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T08:00:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1')), claims=[], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "returned": { "audit": { @@ -193,7 +285,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" diff --git a/tests/fixtures/parity/expected/verify__status_failed.json b/tests/fixtures/parity/expected/verify__status_failed.json index c379a8d..c550bd3 100644 --- a/tests/fixtures/parity/expected/verify__status_failed.json +++ b/tests/fixtures/parity/expected/verify__status_failed.json @@ -22,8 +22,18 @@ "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence", + "error": "Pipeline stopped at: research_empty", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "retryable": false, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "failed — Pipeline stopped at: research_empty\n", "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped at: research_empty\",\n \"failure_reason\": \"research_empty\",\n \"failure_detail\": \"\",\n \"failure_class\": \"insufficient_evidence\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#insufficient-evidence\"\n}\n", + "repr": "TaskStatus(status='failed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[], candidates=[], similar_claims=[], error='Pipeline stopped at: research_empty', failure_reason='research_empty', failure_detail='', failure_class='insufficient_evidence', retryable=False, docs_url='https://lenz.io/docs/errors#insufficient-evidence')", "wait": { "cause": "Pipeline stopped at: research_empty", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_failed_after_a_while.json b/tests/fixtures/parity/expected/verify__status_failed_after_a_while.json index 1de2af6..4714bed 100644 --- a/tests/fixtures/parity/expected/verify__status_failed_after_a_while.json +++ b/tests/fixtures/parity/expected/verify__status_failed_after_a_while.json @@ -22,8 +22,18 @@ "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "docs_url": "https://lenz.io/docs/errors#internal", + "error": "Pipeline stopped: conclusion_failed.", + "failure_class": "internal", + "failure_reason": "conclusion_failed", + "retryable": false, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "failed — Pipeline stopped: conclusion_failed.\n", "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped: conclusion_failed.\",\n \"failure_reason\": \"conclusion_failed\",\n \"failure_detail\": \"\",\n \"failure_class\": \"internal\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#internal\"\n}\n", + "repr": "TaskStatus(status='failed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[], candidates=[], similar_claims=[], error='Pipeline stopped: conclusion_failed.', failure_reason='conclusion_failed', failure_detail='', failure_class='internal', retryable=False, docs_url='https://lenz.io/docs/errors#internal')", "wait": { "cause": "Pipeline stopped: conclusion_failed.", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_failed_after_a_while_framing.json b/tests/fixtures/parity/expected/verify__status_failed_after_a_while_framing.json index 52d9c84..635cdf9 100644 --- a/tests/fixtures/parity/expected/verify__status_failed_after_a_while_framing.json +++ b/tests/fixtures/parity/expected/verify__status_failed_after_a_while_framing.json @@ -22,8 +22,18 @@ "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "error": "Pipeline stopped: framing_failed.", + "failure_class": "upstream_unavailable", + "failure_reason": "framing_failed", + "retryable": true, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "failed — Pipeline stopped: framing_failed.\n", "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped: framing_failed.\",\n \"failure_reason\": \"framing_failed\",\n \"failure_detail\": \"\",\n \"failure_class\": \"upstream_unavailable\",\n \"retryable\": true,\n \"docs_url\": \"https://lenz.io/docs/errors#upstream-unavailable\"\n}\n", + "repr": "TaskStatus(status='failed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[], candidates=[], similar_claims=[], error='Pipeline stopped: framing_failed.', failure_reason='framing_failed', failure_detail='', failure_class='upstream_unavailable', retryable=True, docs_url='https://lenz.io/docs/errors#upstream-unavailable')", "wait": { "cause": "Pipeline stopped: framing_failed.", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_failed_retryable.json b/tests/fixtures/parity/expected/verify__status_failed_retryable.json index fbe1bf9..f49b1cc 100644 --- a/tests/fixtures/parity/expected/verify__status_failed_retryable.json +++ b/tests/fixtures/parity/expected/verify__status_failed_retryable.json @@ -22,8 +22,18 @@ "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "error": "Pipeline stopped at: adjudication_failed", + "failure_class": "upstream_unavailable", + "failure_reason": "adjudication_failed", + "retryable": true, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "failed — Pipeline stopped at: adjudication_failed\n", "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped at: adjudication_failed\",\n \"failure_reason\": \"adjudication_failed\",\n \"failure_detail\": \"\",\n \"failure_class\": \"upstream_unavailable\",\n \"retryable\": true,\n \"docs_url\": \"https://lenz.io/docs/errors#upstream-unavailable\"\n}\n", + "repr": "TaskStatus(status='failed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[], candidates=[], similar_claims=[], error='Pipeline stopped at: adjudication_failed', failure_reason='adjudication_failed', failure_detail='', failure_class='upstream_unavailable', retryable=True, docs_url='https://lenz.io/docs/errors#upstream-unavailable')", "wait": { "cause": "Pipeline stopped at: adjudication_failed", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_needs_input.json b/tests/fixtures/parity/expected/verify__status_needs_input.json index 13a266b..0a1ff14 100644 --- a/tests/fixtures/parity/expected/verify__status_needs_input.json +++ b/tests/fixtures/parity/expected/verify__status_needs_input.json @@ -31,8 +31,25 @@ "status": "needs_input", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "claims": [ + { + "domain": "Science", + "text": "The Earth is round." + }, + { + "domain": "Science", + "text": "Water boils at 100C at sea level." + } + ], + "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.", + "reason": "multi_claim", + "status": "needs_input", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "needs input (multi_claim)\nclaims found:\n 1. The Earth is round.\n 2. Water boils at 100C at sea level.\nresolve it: lenz verify --resume t --claim --detach\n", "render_json": "{\n \"status\": \"needs_input\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"multi_claim\",\n \"hint\": \"The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [\n {\n \"text\": \"The Earth is round.\",\n \"domain\": \"Science\"\n },\n {\n \"text\": \"Water boils at 100C at sea level.\",\n \"domain\": \"Science\"\n }\n ],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "repr": "TaskStatus(status='needs_input', task_id='7cff18da2d979d6370e54a160be121ad', reason='multi_claim', hint='The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[CandidateClaim(text='The Earth is round.', domain='Science'), CandidateClaim(text='Water boils at 100C at sea level.', domain='Science')], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "cause": "The verification needs caller input to proceed.", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_not_a_claim.json b/tests/fixtures/parity/expected/verify__status_not_a_claim.json index 5f7f1c5..1007c6e 100644 --- a/tests/fixtures/parity/expected/verify__status_not_a_claim.json +++ b/tests/fixtures/parity/expected/verify__status_not_a_claim.json @@ -22,8 +22,19 @@ "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "error": "Not a verifiable claim.", + "failure_class": "invalid_input", + "failure_reason": "not_a_claim", + "hint": "The input is a greeting, not a statement that can be checked. Send one factual claim, or run the text through /extract to enumerate its claims.", + "retryable": false, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "failed — Not a verifiable claim.\n", "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"The input is a greeting, not a statement that can be checked. Send one factual claim, or run the text through /extract to enumerate its claims.\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Not a verifiable claim.\",\n \"failure_reason\": \"not_a_claim\",\n \"failure_detail\": \"\",\n \"failure_class\": \"invalid_input\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#invalid-input\"\n}\n", + "repr": "TaskStatus(status='failed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='The input is a greeting, not a statement that can be checked. Send one factual claim, or run the text through /extract to enumerate its claims.', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[], candidates=[], similar_claims=[], error='Not a verifiable claim.', failure_reason='not_a_claim', failure_detail='', failure_class='invalid_input', retryable=False, docs_url='https://lenz.io/docs/errors#invalid-input')", "wait": { "cause": "Not a verifiable claim.", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_not_a_claim_after_a_while.json b/tests/fixtures/parity/expected/verify__status_not_a_claim_after_a_while.json index 422b2c4..d056d07 100644 --- a/tests/fixtures/parity/expected/verify__status_not_a_claim_after_a_while.json +++ b/tests/fixtures/parity/expected/verify__status_not_a_claim_after_a_while.json @@ -22,8 +22,18 @@ "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "docs_url": "https://lenz.io/docs/errors#invalid-input", + "error": "Pipeline stopped: not_a_claim.", + "failure_class": "invalid_input", + "failure_reason": "not_a_claim", + "retryable": false, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "failed — Pipeline stopped: not_a_claim.\n", "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped: not_a_claim.\",\n \"failure_reason\": \"not_a_claim\",\n \"failure_detail\": \"\",\n \"failure_class\": \"invalid_input\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#invalid-input\"\n}\n", + "repr": "TaskStatus(status='failed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[], candidates=[], similar_claims=[], error='Pipeline stopped: not_a_claim.', failure_reason='not_a_claim', failure_detail='', failure_class='invalid_input', retryable=False, docs_url='https://lenz.io/docs/errors#invalid-input')", "wait": { "cause": "Pipeline stopped: not_a_claim.", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_older_run_completed.json b/tests/fixtures/parity/expected/verify__status_older_run_completed.json index 4455d97..9f88760 100644 --- a/tests/fixtures/parity/expected/verify__status_older_run_completed.json +++ b/tests/fixtures/parity/expected/verify__status_older_run_completed.json @@ -64,7 +64,7 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -97,7 +97,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" @@ -108,9 +108,101 @@ "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render": "True (high) score 9/10\n\nverification_id: 4d44dfaf\nfull report: lenz show 4d44dfaf\n", - "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"4d44dfaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:21:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", - "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 4d44dfaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 4d44dfaf \"\"\n", + "dump_unset": { + "result": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render": "True (high) score 9/10\n\nverification_id: 68ca4aaf\nfull report: lenz show 68ca4aaf\n", + "render_json": "{\n \"status\": \"completed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": {\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n },\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_verification": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", + "repr": "TaskStatus(status='completed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1')), claims=[], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "returned": { "audit": { @@ -160,7 +252,7 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -193,7 +285,7 @@ ], "suggested_rewrite": null, "verdict": "True", - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "visibility": "private", "warnings": [ "Relies on limited sources" diff --git a/tests/fixtures/parity/expected/verify__status_older_run_failed_crashed.json b/tests/fixtures/parity/expected/verify__status_older_run_failed_crashed.json index 6700b6d..04bfe69 100644 --- a/tests/fixtures/parity/expected/verify__status_older_run_failed_crashed.json +++ b/tests/fixtures/parity/expected/verify__status_older_run_failed_crashed.json @@ -22,8 +22,18 @@ "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "docs_url": "https://lenz.io/docs/errors#internal", + "error": "Pipeline failed.", + "failure_class": "internal", + "failure_reason": "task_error", + "retryable": false, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "failed — Pipeline failed.\n", "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline failed.\",\n \"failure_reason\": \"task_error\",\n \"failure_detail\": \"\",\n \"failure_class\": \"internal\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#internal\"\n}\n", + "repr": "TaskStatus(status='failed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[], candidates=[], similar_claims=[], error='Pipeline failed.', failure_reason='task_error', failure_detail='', failure_class='internal', retryable=False, docs_url='https://lenz.io/docs/errors#internal')", "wait": { "cause": "Pipeline failed.", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_older_run_failed_insufficient_evidence.json b/tests/fixtures/parity/expected/verify__status_older_run_failed_insufficient_evidence.json index c379a8d..c550bd3 100644 --- a/tests/fixtures/parity/expected/verify__status_older_run_failed_insufficient_evidence.json +++ b/tests/fixtures/parity/expected/verify__status_older_run_failed_insufficient_evidence.json @@ -22,8 +22,18 @@ "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "docs_url": "https://lenz.io/docs/errors#insufficient-evidence", + "error": "Pipeline stopped at: research_empty", + "failure_class": "insufficient_evidence", + "failure_reason": "research_empty", + "retryable": false, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "failed — Pipeline stopped at: research_empty\n", "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"Pipeline stopped at: research_empty\",\n \"failure_reason\": \"research_empty\",\n \"failure_detail\": \"\",\n \"failure_class\": \"insufficient_evidence\",\n \"retryable\": false,\n \"docs_url\": \"https://lenz.io/docs/errors#insufficient-evidence\"\n}\n", + "repr": "TaskStatus(status='failed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[], candidates=[], similar_claims=[], error='Pipeline stopped at: research_empty', failure_reason='research_empty', failure_detail='', failure_class='insufficient_evidence', retryable=False, docs_url='https://lenz.io/docs/errors#insufficient-evidence')", "wait": { "cause": "Pipeline stopped at: research_empty", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_older_run_in_progress.json b/tests/fixtures/parity/expected/verify__status_older_run_in_progress.json index fb3142e..01a834c 100644 --- a/tests/fixtures/parity/expected/verify__status_older_run_in_progress.json +++ b/tests/fixtures/parity/expected/verify__status_older_run_in_progress.json @@ -9,7 +9,7 @@ "failure_reason": "", "hint": "", "progress": { - "elapsed_seconds": 2, + "elapsed_seconds": 1, "index": 2, "poll_after_seconds": 5, "step": "research", @@ -22,8 +22,20 @@ "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "progress": { + "elapsed_seconds": 1, + "index": 2, + "poll_after_seconds": 5, + "step": "research", + "total": 5 + }, + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "processing — Gathering evidence (2/5)\n", - "render_json": "{\n \"status\": \"processing\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"research\",\n \"index\": 2,\n \"total\": 5,\n \"elapsed_seconds\": 2,\n \"poll_after_seconds\": 5\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_json": "{\n \"status\": \"processing\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"research\",\n \"index\": 2,\n \"total\": 5,\n \"elapsed_seconds\": 1,\n \"poll_after_seconds\": 5\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "repr": "TaskStatus(status='processing', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='research', index=2, total=5, elapsed_seconds=1, poll_after_seconds=5), result=None, claims=[], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "cause": "unknown", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_processing.json b/tests/fixtures/parity/expected/verify__status_processing.json index fb3142e..01a834c 100644 --- a/tests/fixtures/parity/expected/verify__status_processing.json +++ b/tests/fixtures/parity/expected/verify__status_processing.json @@ -9,7 +9,7 @@ "failure_reason": "", "hint": "", "progress": { - "elapsed_seconds": 2, + "elapsed_seconds": 1, "index": 2, "poll_after_seconds": 5, "step": "research", @@ -22,8 +22,20 @@ "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "progress": { + "elapsed_seconds": 1, + "index": 2, + "poll_after_seconds": 5, + "step": "research", + "total": 5 + }, + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "processing — Gathering evidence (2/5)\n", - "render_json": "{\n \"status\": \"processing\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"research\",\n \"index\": 2,\n \"total\": 5,\n \"elapsed_seconds\": 2,\n \"poll_after_seconds\": 5\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_json": "{\n \"status\": \"processing\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"research\",\n \"index\": 2,\n \"total\": 5,\n \"elapsed_seconds\": 1,\n \"poll_after_seconds\": 5\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "repr": "TaskStatus(status='processing', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='research', index=2, total=5, elapsed_seconds=1, poll_after_seconds=5), result=None, claims=[], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "cause": "unknown", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_processing_after_a_while.json b/tests/fixtures/parity/expected/verify__status_processing_after_a_while.json index e7bb01d..03a199c 100644 --- a/tests/fixtures/parity/expected/verify__status_processing_after_a_while.json +++ b/tests/fixtures/parity/expected/verify__status_processing_after_a_while.json @@ -9,7 +9,7 @@ "failure_reason": "", "hint": "", "progress": { - "elapsed_seconds": 2, + "elapsed_seconds": 1, "index": 4, "poll_after_seconds": 5, "step": "adjudication", @@ -22,8 +22,20 @@ "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "progress": { + "elapsed_seconds": 1, + "index": 4, + "poll_after_seconds": 5, + "step": "adjudication", + "total": 5 + }, + "status": "processing", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "processing — Panel review across models (4/5)\n", - "render_json": "{\n \"status\": \"processing\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"adjudication\",\n \"index\": 4,\n \"total\": 5,\n \"elapsed_seconds\": 2,\n \"poll_after_seconds\": 5\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "render_json": "{\n \"status\": \"processing\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"adjudication\",\n \"index\": 4,\n \"total\": 5,\n \"elapsed_seconds\": 1,\n \"poll_after_seconds\": 5\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"\",\n \"failure_reason\": \"\",\n \"failure_detail\": \"\",\n \"failure_class\": \"\",\n \"retryable\": null,\n \"docs_url\": \"\"\n}\n", + "repr": "TaskStatus(status='processing', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='adjudication', index=4, total=5, elapsed_seconds=1, poll_after_seconds=5), result=None, claims=[], candidates=[], similar_claims=[], error='', failure_reason='', failure_detail='', failure_class='', retryable=None, docs_url='')", "wait": { "cause": "unknown", "code": "", diff --git a/tests/fixtures/parity/expected/verify__status_task_stuck.json b/tests/fixtures/parity/expected/verify__status_task_stuck.json index d7e9b4b..db68477 100644 --- a/tests/fixtures/parity/expected/verify__status_task_stuck.json +++ b/tests/fixtures/parity/expected/verify__status_task_stuck.json @@ -22,8 +22,18 @@ "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad" }, + "dump_unset": { + "docs_url": "https://lenz.io/docs/errors#upstream-unavailable", + "error": "The task was never completed and has been marked failed.", + "failure_class": "upstream_unavailable", + "failure_reason": "task_stuck", + "retryable": true, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "render": "failed — The task was never completed and has been marked failed.\n", "render_json": "{\n \"status\": \"failed\",\n \"task_id\": \"7cff18da2d979d6370e54a160be121ad\",\n \"reason\": \"\",\n \"hint\": \"\",\n \"progress\": {\n \"step\": \"\",\n \"index\": null,\n \"total\": null,\n \"elapsed_seconds\": null,\n \"poll_after_seconds\": null\n },\n \"result\": null,\n \"claims\": [],\n \"candidates\": [],\n \"similar_claims\": [],\n \"error\": \"The task was never completed and has been marked failed.\",\n \"failure_reason\": \"task_stuck\",\n \"failure_detail\": \"\",\n \"failure_class\": \"upstream_unavailable\",\n \"retryable\": true,\n \"docs_url\": \"https://lenz.io/docs/errors#upstream-unavailable\"\n}\n", + "repr": "TaskStatus(status='failed', task_id='7cff18da2d979d6370e54a160be121ad', reason='', hint='', progress=Progress(step='', index=None, total=None, elapsed_seconds=None, poll_after_seconds=None), result=None, claims=[], candidates=[], similar_claims=[], error='The task was never completed and has been marked failed.', failure_reason='task_stuck', failure_detail='', failure_class='upstream_unavailable', retryable=True, docs_url='https://lenz.io/docs/errors#upstream-unavailable')", "wait": { "cause": "The task was never completed and has been marked failed.", "code": "", diff --git a/tests/fixtures/parity/expected/verify__submit_202.json b/tests/fixtures/parity/expected/verify__submit_202.json index 4aa7f3a..74a0269 100644 --- a/tests/fixtures/parity/expected/verify__submit_202.json +++ b/tests/fixtures/parity/expected/verify__submit_202.json @@ -1,9 +1,15 @@ { "dump": { - "chain_id": "78ac4e9f234ea3bd", + "chain_id": "99a0a9ca89e1e72c", "claim_text": "", "status": "queued", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render_json": null + "dump_unset": { + "chain_id": "99a0a9ca89e1e72c", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null, + "repr": "TaskAccepted(task_id='7cff18da2d979d6370e54a160be121ad', claim_text='', status='queued', chain_id='99a0a9ca89e1e72c')" } diff --git a/tests/fixtures/parity/expected/verify__submit_202_options.json b/tests/fixtures/parity/expected/verify__submit_202_options.json index 4aa7f3a..74a0269 100644 --- a/tests/fixtures/parity/expected/verify__submit_202_options.json +++ b/tests/fixtures/parity/expected/verify__submit_202_options.json @@ -1,9 +1,15 @@ { "dump": { - "chain_id": "78ac4e9f234ea3bd", + "chain_id": "99a0a9ca89e1e72c", "claim_text": "", "status": "queued", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render_json": null + "dump_unset": { + "chain_id": "99a0a9ca89e1e72c", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null, + "repr": "TaskAccepted(task_id='7cff18da2d979d6370e54a160be121ad', claim_text='', status='queued', chain_id='99a0a9ca89e1e72c')" } diff --git a/tests/fixtures/parity/expected/verify__submit_202_text_alias.json b/tests/fixtures/parity/expected/verify__submit_202_text_alias.json index 4aa7f3a..74a0269 100644 --- a/tests/fixtures/parity/expected/verify__submit_202_text_alias.json +++ b/tests/fixtures/parity/expected/verify__submit_202_text_alias.json @@ -1,9 +1,15 @@ { "dump": { - "chain_id": "78ac4e9f234ea3bd", + "chain_id": "99a0a9ca89e1e72c", "claim_text": "", "status": "queued", "task_id": "7cff18da2d979d6370e54a160be121ad" }, - "render_json": null + "dump_unset": { + "chain_id": "99a0a9ca89e1e72c", + "status": "queued", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, + "render_json": null, + "repr": "TaskAccepted(task_id='7cff18da2d979d6370e54a160be121ad', claim_text='', status='queued', chain_id='99a0a9ca89e1e72c')" } diff --git a/tests/fixtures/parity/expected/verify__verification_200.json b/tests/fixtures/parity/expected/verify__verification_200.json index 9c9202f..8ec0e7a 100644 --- a/tests/fixtures/parity/expected/verify__verification_200.json +++ b/tests/fixtures/parity/expected/verify__verification_200.json @@ -47,7 +47,94 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "dump_unset": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -88,5 +175,6 @@ }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_200_covered.json b/tests/fixtures/parity/expected/verify__verification_200_covered.json index 9e542b8..ed0c52c 100644 --- a/tests/fixtures/parity/expected/verify__verification_200_covered.json +++ b/tests/fixtures/parity/expected/verify__verification_200_covered.json @@ -38,14 +38,99 @@ "aggregate": 500000, "as_of": "2026-03-10T12:01:30+00:00", "cap": 10000, - "certificate_id": "def7232d27eda03cf261569aee9948c5", - "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "certificate_id": "95b0f3dd008b46846b6dd6b15099e2b3", + "certificate_url": "https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3", "currency": "EUR", "reasons": [], "status": "covered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "dump_unset": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": "2026-03-10T12:01:30+00:00", + "cap": 10000, + "certificate_id": "95b0f3dd008b46846b6dd6b15099e2b3", + "certificate_url": "https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3", + "currency": "EUR", + "reasons": [], + "status": "covered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -86,5 +171,6 @@ }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"covered\",\n \"reasons\": [],\n \"certificate_id\": \"def7232d27eda03cf261569aee9948c5\",\n \"certificate_url\": \"https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5\",\n \"as_of\": \"2026-03-10T12:01:30+00:00\",\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"covered\",\n \"reasons\": [],\n \"certificate_id\": \"95b0f3dd008b46846b6dd6b15099e2b3\",\n \"certificate_url\": \"https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3\",\n \"as_of\": \"2026-03-10T12:01:30+00:00\",\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='covered', reasons=[], certificate_id='95b0f3dd008b46846b6dd6b15099e2b3', certificate_url='https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3', as_of='2026-03-10T12:01:30+00:00', currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/verify__verification_200_modified_at_crosses_midnight_by_minutes.json index fc049f4..ab23f79 100644 --- a/tests/fixtures/parity/expected/verify__verification_200_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/expected/verify__verification_200_modified_at_crosses_midnight_by_minutes.json @@ -86,7 +86,95 @@ "Relies on limited sources" ] }, + "dump_unset": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T23:55:00.123456+00:00', modified_at='2026-10-02T00:03:00.123456+00:00', language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_200_modified_at_null.json b/tests/fixtures/parity/expected/verify__verification_200_modified_at_null.json index 9c9202f..8ec0e7a 100644 --- a/tests/fixtures/parity/expected/verify__verification_200_modified_at_null.json +++ b/tests/fixtures/parity/expected/verify__verification_200_modified_at_null.json @@ -47,7 +47,94 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "dump_unset": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -88,5 +175,6 @@ }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/verify__verification_200_modified_at_same_day_hours_apart.json index 11aaf1c..6e45445 100644 --- a/tests/fixtures/parity/expected/verify__verification_200_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/expected/verify__verification_200_modified_at_same_day_hours_apart.json @@ -86,7 +86,95 @@ "Relies on limited sources" ] }, + "dump_unset": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T08:00:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T08:00:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T08:00:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T08:00:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_200_modified_at_set.json b/tests/fixtures/parity/expected/verify__verification_200_modified_at_set.json index fc049f4..ab23f79 100644 --- a/tests/fixtures/parity/expected/verify__verification_200_modified_at_set.json +++ b/tests/fixtures/parity/expected/verify__verification_200_modified_at_set.json @@ -86,7 +86,95 @@ "Relies on limited sources" ] }, + "dump_unset": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T23:55:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": "2026-10-02T00:03:00.123456+00:00", + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T23:55:00.123456+00:00\",\n \"modified_at\": \"2026-10-02T00:03:00.123456+00:00\",\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T23:55:00.123456+00:00', modified_at='2026-10-02T00:03:00.123456+00:00', language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_200_result_json_conclusion_only.json b/tests/fixtures/parity/expected/verify__verification_200_result_json_conclusion_only.json index 7df6e17..30e90b7 100644 --- a/tests/fixtures/parity/expected/verify__verification_200_result_json_conclusion_only.json +++ b/tests/fixtures/parity/expected/verify__verification_200_result_json_conclusion_only.json @@ -30,7 +30,55 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "", + "sources": [], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [] + }, + "dump_unset": { + "audit": { + "adjudication_summary": "", + "assessments": [], + "debate_con": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "debate_pro": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "panel_agreement": "split" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [], @@ -49,5 +97,6 @@ }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\n── Panel ──\nagreement: split\n\nDebate\n PRO \n CON \n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [],\n \"presumed_intent\": \"\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [],\n \"suggested_rewrite\": null,\n \"sources\": [],\n \"audit\": {\n \"adjudication_summary\": \"\",\n \"assessments\": [],\n \"debate_pro\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"debate_con\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"panel_agreement\": \"split\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [],\n \"presumed_intent\": \"\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [],\n \"suggested_rewrite\": null,\n \"sources\": [],\n \"audit\": {\n \"adjudication_summary\": \"\",\n \"assessments\": [],\n \"debate_pro\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"debate_con\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"panel_agreement\": \"split\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[], presumed_intent='', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=[], suggested_rewrite=None, sources=[], audit=Audit(adjudication_summary='', assessments=[], debate_pro=DebateSide(role='', argument='', rebuttal=''), debate_con=DebateSide(role='', argument='', rebuttal=''), panel_agreement='split'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_200_result_json_empty.json b/tests/fixtures/parity/expected/verify__verification_200_result_json_empty.json index 7df6e17..30e90b7 100644 --- a/tests/fixtures/parity/expected/verify__verification_200_result_json_empty.json +++ b/tests/fixtures/parity/expected/verify__verification_200_result_json_empty.json @@ -30,7 +30,55 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "", + "sources": [], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [] + }, + "dump_unset": { + "audit": { + "adjudication_summary": "", + "assessments": [], + "debate_con": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "debate_pro": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "panel_agreement": "split" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [], @@ -49,5 +97,6 @@ }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\n── Panel ──\nagreement: split\n\nDebate\n PRO \n CON \n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [],\n \"presumed_intent\": \"\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [],\n \"suggested_rewrite\": null,\n \"sources\": [],\n \"audit\": {\n \"adjudication_summary\": \"\",\n \"assessments\": [],\n \"debate_pro\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"debate_con\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"panel_agreement\": \"split\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [],\n \"presumed_intent\": \"\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [],\n \"suggested_rewrite\": null,\n \"sources\": [],\n \"audit\": {\n \"adjudication_summary\": \"\",\n \"assessments\": [],\n \"debate_pro\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"debate_con\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"panel_agreement\": \"split\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[], presumed_intent='', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=[], suggested_rewrite=None, sources=[], audit=Audit(adjudication_summary='', assessments=[], debate_pro=DebateSide(role='', argument='', rebuttal=''), debate_con=DebateSide(role='', argument='', rebuttal=''), panel_agreement='split'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_200_result_json_old_shape_strings.json b/tests/fixtures/parity/expected/verify__verification_200_result_json_old_shape_strings.json index a8398f8..f9f875f 100644 --- a/tests/fixtures/parity/expected/verify__verification_200_result_json_old_shape_strings.json +++ b/tests/fixtures/parity/expected/verify__verification_200_result_json_old_shape_strings.json @@ -38,7 +38,71 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "", + "sources": [ + { + "date": "", + "snippet": "Old row.", + "source_name": "", + "title": "", + "url": "https://old.example/a" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [] + }, + "dump_unset": { + "audit": { + "adjudication_summary": "", + "assessments": [ + { + "focus_area": "", + "panelist_name": "Reviewer A", + "reasoning": "", + "score": null, + "warnings": [] + } + ], + "debate_con": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "debate_pro": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "panel_agreement": "split" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [], @@ -65,5 +129,6 @@ }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (1):\n • https://old.example/a\n https://old.example/a\n Old row.\n\n── Panel ──\nagreement: split\n\nReviewer A\n\nDebate\n PRO \n CON \n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (1):\n • https://old.example/a\n https://old.example/a\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [],\n \"presumed_intent\": \"\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"\",\n \"title\": \"\",\n \"url\": \"https://old.example/a\",\n \"snippet\": \"Old row.\",\n \"date\": \"\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"\",\n \"score\": null,\n \"reasoning\": \"\",\n \"warnings\": []\n }\n ],\n \"debate_pro\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"debate_con\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"panel_agreement\": \"split\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [],\n \"presumed_intent\": \"\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"\",\n \"title\": \"\",\n \"url\": \"https://old.example/a\",\n \"snippet\": \"Old row.\",\n \"date\": \"\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"\",\n \"score\": null,\n \"reasoning\": \"\",\n \"warnings\": []\n }\n ],\n \"debate_pro\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"debate_con\": {\n \"role\": \"\",\n \"argument\": \"\",\n \"rebuttal\": \"\"\n },\n \"panel_agreement\": \"split\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[], presumed_intent='', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=[], suggested_rewrite=None, sources=[Source(source_name='', title='', url='https://old.example/a', snippet='Old row.', date='')], audit=Audit(adjudication_summary='', assessments=[Assessment(panelist_name='Reviewer A', focus_area='', score=None, reasoning='', warnings=[])], debate_pro=DebateSide(role='', argument='', rebuttal=''), debate_con=DebateSide(role='', argument='', rebuttal=''), panel_agreement='split'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_by_task_id_200.json b/tests/fixtures/parity/expected/verify__verification_by_task_id_200.json index 9c9202f..8ec0e7a 100644 --- a/tests/fixtures/parity/expected/verify__verification_by_task_id_200.json +++ b/tests/fixtures/parity/expected/verify__verification_by_task_id_200.json @@ -47,7 +47,94 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "dump_unset": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -88,5 +175,6 @@ }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_public_anonymous.json b/tests/fixtures/parity/expected/verify__verification_public_anonymous.json index ab58772..7319f6f 100644 --- a/tests/fixtures/parity/expected/verify__verification_public_anonymous.json +++ b/tests/fixtures/parity/expected/verify__verification_public_anonymous.json @@ -35,7 +35,82 @@ "claim": "The Earth is round.", "confidence": "high", "coverage": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "public", + "warnings": [ + "Relies on limited sources" + ] + }, + "dump_unset": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": null, + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -76,5 +151,6 @@ }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"public\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": null\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"public\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": null\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='public', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=None)" } diff --git a/tests/fixtures/parity/expected/verify__verification_public_of_another_user.json b/tests/fixtures/parity/expected/verify__verification_public_of_another_user.json index d21e90e..dc75e23 100644 --- a/tests/fixtures/parity/expected/verify__verification_public_of_another_user.json +++ b/tests/fixtures/parity/expected/verify__verification_public_of_another_user.json @@ -47,7 +47,94 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is verified.", + "key_finding": "The Earth is approximately spherical in shape.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "public", + "warnings": [ + "Relies on limited sources" + ] + }, + "dump_unset": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -88,5 +175,6 @@ }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical in shape.\n\nThe claim is verified.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"public\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"public\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical in shape.\",\n \"executive_summary\": \"The claim is verified.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='public', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical in shape.', executive_summary='The claim is verified.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__verification_zero_retention_served.json b/tests/fixtures/parity/expected/verify__verification_zero_retention_served.json index e12b093..463876f 100644 --- a/tests/fixtures/parity/expected/verify__verification_zero_retention_served.json +++ b/tests/fixtures/parity/expected/verify__verification_zero_retention_served.json @@ -47,7 +47,94 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", + "depth": "standard", + "domain": "Science", + "entities": [ + { + "name": "Earth", + "qid": null + } + ], + "executive_summary": "The claim is well supported by evidence.", + "key_finding": "The Earth is approximately spherical.", + "language": "en", + "lenz_score": 9, + "modified_at": null, + "presumed_intent": "Verify a basic scientific fact", + "sources": [ + { + "date": "2025-01-15", + "snippet": "Satellite imagery shows an oblate spheroid.", + "source_name": "NASA", + "title": "The shape of the Earth", + "url": "https://nasa.example/shape" + }, + { + "date": "2025-01-16", + "snippet": "Orbital measurements confirm the curvature.", + "source_name": "ESA", + "title": "Earth from space", + "url": "https://esa.example/earth" + } + ], + "suggested_rewrite": null, + "verdict": "True", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [ + "Relies on limited sources" + ] + }, + "dump_unset": { + "audit": { + "adjudication_summary": "Both reviewers agreed.", + "assessments": [ + { + "focus_area": "Claim Precision & Quantitative Accuracy", + "panelist_name": "Reviewer A", + "reasoning": "Precision analysis reasoning.", + "score": 9.0, + "warnings": [] + }, + { + "focus_area": "Sources", + "panelist_name": "Reviewer B", + "reasoning": "Source audit reasoning.", + "score": 9.0, + "warnings": [ + "weak source A" + ] + } + ], + "debate_con": { + "argument": "The Earth is not a perfect sphere.", + "rebuttal": "Oblate, but round for the claim.", + "role": "Skeptic" + }, + "debate_pro": { + "argument": "Satellite imagery and geodesy agree.", + "rebuttal": "Flat-Earth objections do not hold.", + "role": "Advocate" + }, + "panel_agreement": "unanimous" + }, + "claim": "The Earth is round.", + "confidence": "high", + "coverage": { + "aggregate": 500000, + "as_of": null, + "cap": 10000, + "certificate_id": null, + "certificate_url": null, + "currency": "EUR", + "reasons": [ + "plan" + ], + "status": "uncovered", + "terms_version": "v1" + }, + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Science", "entities": [ @@ -88,5 +175,6 @@ }, "render": "True (high) score 9/10\n\nClaim The Earth is round.\nScience • Earth\n\nThe Earth is approximately spherical.\n\nThe claim is well supported by evidence.\n\nWarnings (1):\n • Relies on limited sources\n\nSources (2):\n • The shape of the Earth (2025-01-15)\n https://nasa.example/shape\n Satellite imagery shows an oblate spheroid.\n • Earth from space (2025-01-16)\n https://esa.example/earth\n Orbital measurements confirm the curvature.\n\n── Panel ──\nagreement: unanimous\n\nReviewer A (Claim Precision & Quantitative Accuracy) 9.0/10\n Precision analysis reasoning.\n\nReviewer B (Sources) 9.0/10\n Source audit reasoning.\n • weak source A\n\nPanel Review\nBoth reviewers agreed.\n\nDebate\n PRO Satellite imagery and geodesy agree.\n rebuttal: Flat-Earth objections do not hold.\n CON The Earth is not a perfect sphere.\n rebuttal: Oblate, but round for the claim.\n\nverification_id: 68ca4aaf\nchecked Oct 1, 2026\nask follow-ups: lenz ask 68ca4aaf \"\"\n", "render_concise": "True (high) score 9/10\n\nThe Earth is approximately spherical.\n\nThe claim is well supported by evidence.\n\nSources (2):\n • The shape of the Earth\n https://nasa.example/shape\n • Earth from space\n https://esa.example/earth\n\nverification_id: 68ca4aaf\nask follow-ups: lenz ask 68ca4aaf \"\"\n", - "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical.\",\n \"executive_summary\": \"The claim is well supported by evidence.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:14:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n" + "render_json": "{\n \"verification_id\": \"68ca4aaf\",\n \"claim\": \"The Earth is round.\",\n \"visibility\": \"private\",\n \"depth\": \"standard\",\n \"domain\": \"Science\",\n \"entities\": [\n {\n \"name\": \"Earth\",\n \"qid\": null\n }\n ],\n \"presumed_intent\": \"Verify a basic scientific fact\",\n \"verdict\": \"True\",\n \"confidence\": \"high\",\n \"lenz_score\": 9,\n \"key_finding\": \"The Earth is approximately spherical.\",\n \"executive_summary\": \"The claim is well supported by evidence.\",\n \"warnings\": [\n \"Relies on limited sources\"\n ],\n \"suggested_rewrite\": null,\n \"sources\": [\n {\n \"source_name\": \"NASA\",\n \"title\": \"The shape of the Earth\",\n \"url\": \"https://nasa.example/shape\",\n \"snippet\": \"Satellite imagery shows an oblate spheroid.\",\n \"date\": \"2025-01-15\"\n },\n {\n \"source_name\": \"ESA\",\n \"title\": \"Earth from space\",\n \"url\": \"https://esa.example/earth\",\n \"snippet\": \"Orbital measurements confirm the curvature.\",\n \"date\": \"2025-01-16\"\n }\n ],\n \"audit\": {\n \"adjudication_summary\": \"Both reviewers agreed.\",\n \"assessments\": [\n {\n \"panelist_name\": \"Reviewer A\",\n \"focus_area\": \"Claim Precision & Quantitative Accuracy\",\n \"score\": 9.0,\n \"reasoning\": \"Precision analysis reasoning.\",\n \"warnings\": []\n },\n {\n \"panelist_name\": \"Reviewer B\",\n \"focus_area\": \"Sources\",\n \"score\": 9.0,\n \"reasoning\": \"Source audit reasoning.\",\n \"warnings\": [\n \"weak source A\"\n ]\n }\n ],\n \"debate_pro\": {\n \"role\": \"Advocate\",\n \"argument\": \"Satellite imagery and geodesy agree.\",\n \"rebuttal\": \"Flat-Earth objections do not hold.\"\n },\n \"debate_con\": {\n \"role\": \"Skeptic\",\n \"argument\": \"The Earth is not a perfect sphere.\",\n \"rebuttal\": \"Oblate, but round for the claim.\"\n },\n \"panel_agreement\": \"unanimous\"\n },\n \"created_at\": \"2026-10-01T09:07:00.123456+00:00\",\n \"modified_at\": null,\n \"language\": \"en\",\n \"coverage\": {\n \"status\": \"uncovered\",\n \"reasons\": [\n \"plan\"\n ],\n \"certificate_id\": null,\n \"certificate_url\": null,\n \"as_of\": null,\n \"currency\": \"EUR\",\n \"cap\": 10000,\n \"aggregate\": 500000,\n \"terms_version\": \"v1\"\n }\n}\n", + "repr": "Verification(verification_id='68ca4aaf', claim='The Earth is round.', visibility='private', depth='standard', domain='Science', entities=[EntityRef(name='Earth', qid=None)], presumed_intent='Verify a basic scientific fact', verdict='True', confidence='high', lenz_score=9, key_finding='The Earth is approximately spherical.', executive_summary='The claim is well supported by evidence.', warnings=['Relies on limited sources'], suggested_rewrite=None, sources=[Source(source_name='NASA', title='The shape of the Earth', url='https://nasa.example/shape', snippet='Satellite imagery shows an oblate spheroid.', date='2025-01-15'), Source(source_name='ESA', title='Earth from space', url='https://esa.example/earth', snippet='Orbital measurements confirm the curvature.', date='2025-01-16')], audit=Audit(adjudication_summary='Both reviewers agreed.', assessments=[Assessment(panelist_name='Reviewer A', focus_area='Claim Precision & Quantitative Accuracy', score=9.0, reasoning='Precision analysis reasoning.', warnings=[]), Assessment(panelist_name='Reviewer B', focus_area='Sources', score=9.0, reasoning='Source audit reasoning.', warnings=['weak source A'])], debate_pro=DebateSide(role='Advocate', argument='Satellite imagery and geodesy agree.', rebuttal='Flat-Earth objections do not hold.'), debate_con=DebateSide(role='Skeptic', argument='The Earth is not a perfect sphere.', rebuttal='Oblate, but round for the claim.'), panel_agreement='unanimous'), created_at='2026-10-01T09:07:00.123456+00:00', modified_at=None, language='en', coverage=Coverage(status='uncovered', reasons=['plan'], certificate_id=None, certificate_url=None, as_of=None, currency='EUR', cap=10000, aggregate=500000, terms_version='v1'))" } diff --git a/tests/fixtures/parity/expected/verify__webhook_secret_missing_422.json b/tests/fixtures/parity/expected/verify__webhook_secret_missing_422.json new file mode 100644 index 0000000..aa4b7e1 --- /dev/null +++ b/tests/fixtures/parity/expected/verify__webhook_secret_missing_422.json @@ -0,0 +1,22 @@ +{ + "error": { + "cause": "webhook_url was supplied but this API key has no HMAC secret. Generate one at https://lenz.io/api-credentials (Webhooks panel) before submitting webhook-delivered calls.", + "code": "webhook_secret_missing", + "doc_url": "https://lenz.io/docs/errors/validation", + "errors": [], + "fix": "Check the request body against the OpenAPI spec.", + "friendly_text": "webhook_url was supplied but this API key has no HMAC secret. Generate one at https://lenz.io/api-credentials (Webhooks panel) before submitting webhook-delivered calls.\n Fix: Check the request body against the OpenAPI spec.", + "message": "webhook_url was supplied but this API key has no HMAC secret. Generate one at https://lenz.io/api-credentials (Webhooks panel) before submitting webhook-delivered calls.", + "payload_json": { + "error": { + "code": "invalid_request", + "fix": "Check the request body against the OpenAPI spec.", + "message": "webhook_url was supplied but this API key has no HMAC secret. Generate one at https://lenz.io/api-credentials (Webhooks panel) before submitting webhook-delivered calls.", + "status": 422 + } + }, + "request_id": "", + "status_code": 422, + "type": "LenzValidationError" + } +} diff --git a/tests/fixtures/parity/expected/webhook__certificate_timestamped.json b/tests/fixtures/parity/expected/webhook__certificate_timestamped.json index 49e54c1..754e890 100644 --- a/tests/fixtures/parity/expected/webhook__certificate_timestamped.json +++ b/tests/fixtures/parity/expected/webhook__certificate_timestamped.json @@ -6,17 +6,17 @@ "aggregate": 500000, "as_of": "2026-09-03T10:00:00+00:00", "cap": 10000, - "certificate_id": "def7232d27eda03cf261569aee9948c5", - "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "certificate_id": "95b0f3dd008b46846b6dd6b15099e2b3", + "certificate_url": "https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3", "currency": "EUR", "reasons": [], "status": "covered", "terms_version": "v1" }, - "delivered_at": "2026-10-01T09:28:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "certificate.timestamped", "status": "completed", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "CertificateTimestamped", "verification_id": "68ca4aaf" } diff --git a/tests/fixtures/parity/expected/webhook__certificate_timestamped_review_child.json b/tests/fixtures/parity/expected/webhook__certificate_timestamped_review_child.json index 49e54c1..754e890 100644 --- a/tests/fixtures/parity/expected/webhook__certificate_timestamped_review_child.json +++ b/tests/fixtures/parity/expected/webhook__certificate_timestamped_review_child.json @@ -6,17 +6,17 @@ "aggregate": 500000, "as_of": "2026-09-03T10:00:00+00:00", "cap": 10000, - "certificate_id": "def7232d27eda03cf261569aee9948c5", - "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "certificate_id": "95b0f3dd008b46846b6dd6b15099e2b3", + "certificate_url": "https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3", "currency": "EUR", "reasons": [], "status": "covered", "terms_version": "v1" }, - "delivered_at": "2026-10-01T09:28:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "certificate.timestamped", "status": "completed", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "CertificateTimestamped", "verification_id": "68ca4aaf" } diff --git a/tests/fixtures/parity/expected/webhook__citecheck_completed.json b/tests/fixtures/parity/expected/webhook__citecheck_completed.json index 7044240..0fdf121 100644 --- a/tests/fixtures/parity/expected/webhook__citecheck_completed.json +++ b/tests/fixtures/parity/expected/webhook__citecheck_completed.json @@ -95,9 +95,9 @@ "statement": "The agency said so in a statement." } ], - "citecheck_id": "98c0e7d5", - "completed_at": "2026-10-01T09:35:00.123456Z", - "created_at": "2026-10-01T09:28:00.123456Z", + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 2 }, @@ -123,12 +123,12 @@ "citations_selected": 2 } }, - "citecheck_id": "98c0e7d5", - "delivered_at": "2026-10-01T09:42:00.123456+00:00", + "citecheck_id": "8eb49302", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "citecheck.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", "status": "completed", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "CitecheckEvent", "verification_id": null } diff --git a/tests/fixtures/parity/expected/webhook__citecheck_failed.json b/tests/fixtures/parity/expected/webhook__citecheck_failed.json index aaa4c74..400e0d6 100644 --- a/tests/fixtures/parity/expected/webhook__citecheck_failed.json +++ b/tests/fixtures/parity/expected/webhook__citecheck_failed.json @@ -6,9 +6,9 @@ "citation_failures": [], "citation_issues": [], "citations": [], - "citecheck_id": "98c0e7d5", - "completed_at": "2026-10-01T09:35:00.123456Z", - "created_at": "2026-10-01T09:28:00.123456Z", + "citecheck_id": "8eb49302", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -36,12 +36,12 @@ "citations_selected": null } }, - "citecheck_id": "98c0e7d5", - "delivered_at": "2026-10-01T09:42:00.123456+00:00", + "citecheck_id": "8eb49302", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "citecheck.failed", "event_id": "evt_09301870aba4e8f6ae33ff60", "status": "failed", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "CitecheckEvent", "verification_id": null } diff --git a/tests/fixtures/parity/expected/webhook__review_completed.json b/tests/fixtures/parity/expected/webhook__review_completed.json index 4e39f6b..e1f3697 100644 --- a/tests/fixtures/parity/expected/webhook__review_completed.json +++ b/tests/fixtures/parity/expected/webhook__review_completed.json @@ -2,7 +2,7 @@ "event": { "attempt": 1, "batch_id": null, - "delivered_at": "2026-10-01T10:03:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "review.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", "review": { @@ -44,7 +44,7 @@ "claim": "The Eiffel Tower is in Berlin.", "confidence": "high", "content_status": "available", - "created_at": "2026-10-01T09:56:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "depth": "standard", "domain": "", "entities": [], @@ -56,11 +56,11 @@ "modified_at": null, "status": "completed", "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "task_id": "5ccac77f53ff49328ec134fb29d66542", - "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "8ceed6f0", - "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", + "verification_id": "68ca4aaf", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "visibility": "private", "warnings": [ "w1" @@ -68,8 +68,8 @@ } } ], - "completed_at": "2026-10-01T09:35:00.123456Z", - "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 11 }, @@ -92,11 +92,11 @@ "source": "verification", "suggested_edits": null, "suggested_rewrite": "Fixed: The Eiffel Tower is in Berlin.", - "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "verdict": "False", - "verification_id": "8ceed6f0", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", "verified_claim": null } ], @@ -121,7 +121,7 @@ ] }, "poll_after_seconds": null, - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "completed", "summary": { "assessments": { @@ -148,9 +148,9 @@ }, "view": "full" }, - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "completed", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "ReviewEvent", "verification_id": null } diff --git a/tests/fixtures/parity/expected/webhook__review_completed_key_default_url.json b/tests/fixtures/parity/expected/webhook__review_completed_key_default_url.json index 61e1a22..85da702 100644 --- a/tests/fixtures/parity/expected/webhook__review_completed_key_default_url.json +++ b/tests/fixtures/parity/expected/webhook__review_completed_key_default_url.json @@ -2,7 +2,7 @@ "event": { "attempt": 1, "batch_id": null, - "delivered_at": "2026-10-01T09:42:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "review.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", "review": { @@ -41,8 +41,8 @@ "verification": null } ], - "completed_at": "2026-10-01T09:35:00.123456Z", - "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 1 }, @@ -70,7 +70,7 @@ ] }, "poll_after_seconds": null, - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "completed", "summary": { "assessments": { @@ -97,9 +97,9 @@ }, "view": "full" }, - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "completed", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "ReviewEvent", "verification_id": null } diff --git a/tests/fixtures/parity/expected/webhook__review_completed_oversized_rebuilt.json b/tests/fixtures/parity/expected/webhook__review_completed_oversized_rebuilt.json index 9fd5c6f..048af92 100644 --- a/tests/fixtures/parity/expected/webhook__review_completed_oversized_rebuilt.json +++ b/tests/fixtures/parity/expected/webhook__review_completed_oversized_rebuilt.json @@ -6,9 +6,9 @@ "event": "review.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", "review": null, - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "completed", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "ReviewEvent", "verification_id": null } diff --git a/tests/fixtures/parity/expected/webhook__review_failed.json b/tests/fixtures/parity/expected/webhook__review_failed.json index 08af731..ce0bfb0 100644 --- a/tests/fixtures/parity/expected/webhook__review_failed.json +++ b/tests/fixtures/parity/expected/webhook__review_failed.json @@ -2,7 +2,7 @@ "event": { "attempt": 1, "batch_id": null, - "delivered_at": "2026-10-01T09:42:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "review.failed", "event_id": "evt_09301870aba4e8f6ae33ff60", "review": { @@ -10,8 +10,8 @@ "citation_issues": [], "citations": [], "claims": [], - "completed_at": "2026-10-01T09:35:00.123456Z", - "created_at": "2026-10-01T09:28:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "credits": { "charged": 0 }, @@ -45,7 +45,7 @@ ] }, "poll_after_seconds": null, - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "failed", "summary": { "assessments": null, @@ -65,9 +65,9 @@ }, "view": "full" }, - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "status": "failed", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "ReviewEvent", "verification_id": null } diff --git a/tests/fixtures/parity/expected/webhook__test_fire.json b/tests/fixtures/parity/expected/webhook__test_fire.json new file mode 100644 index 0000000..b796dcd --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__test_fire.json @@ -0,0 +1,12 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T11:07:00.123456+00:00", + "event": "webhook.test", + "status": "test", + "task_id": "test_7cff18da2d979d63", + "type": "WebhookEvent", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_completed.json b/tests/fixtures/parity/expected/webhook__verification_completed.json index aa45bf9..1f8d807 100644 --- a/tests/fixtures/parity/expected/webhook__verification_completed.json +++ b/tests/fixtures/parity/expected/webhook__verification_completed.json @@ -2,7 +2,7 @@ "event": { "attempt": 1, "batch_id": null, - "delivered_at": "2026-10-01T09:28:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "verification.completed", "result": { "audit": { @@ -52,7 +52,7 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Geography", "entities": [ @@ -96,7 +96,7 @@ ] }, "status": "completed", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "VerificationCompleted", "verification_id": "68ca4aaf" } diff --git a/tests/fixtures/parity/expected/webhook__verification_completed_in_batch.json b/tests/fixtures/parity/expected/webhook__verification_completed_in_batch.json index e6dd56f..2fff9b6 100644 --- a/tests/fixtures/parity/expected/webhook__verification_completed_in_batch.json +++ b/tests/fixtures/parity/expected/webhook__verification_completed_in_batch.json @@ -1,8 +1,8 @@ { "event": { "attempt": 1, - "batch_id": "4ee0c3aa1b671eaa", - "delivered_at": "2026-10-01T09:35:00.123456+00:00", + "batch_id": "7ea9cdbd4064e3cf", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "verification.completed", "result": { "audit": { @@ -52,7 +52,7 @@ "status": "uncovered", "terms_version": "v1" }, - "created_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "depth": "standard", "domain": "Geography", "entities": [ @@ -96,7 +96,7 @@ ] }, "status": "completed", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "VerificationCompleted", "verification_id": "68ca4aaf" } diff --git a/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json index c050dad..0edf9aa 100644 --- a/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json @@ -2,7 +2,7 @@ "event": { "attempt": 1, "batch_id": null, - "delivered_at": "2026-10-01T09:35:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "verification.completed", "result": { "audit": { @@ -96,7 +96,7 @@ ] }, "status": "completed", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "VerificationCompleted", "verification_id": "68ca4aaf" } diff --git a/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_same_day_hours_apart.json index 78e81e6..c573ea4 100644 --- a/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/expected/webhook__verification_completed_modified_at_same_day_hours_apart.json @@ -2,7 +2,7 @@ "event": { "attempt": 1, "batch_id": null, - "delivered_at": "2026-10-01T09:28:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "verification.completed", "result": { "audit": { @@ -96,7 +96,7 @@ ] }, "status": "completed", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "type": "VerificationCompleted", "verification_id": "68ca4aaf" } diff --git a/tests/fixtures/parity/expected/webhook__verification_completed_sparse_result.json b/tests/fixtures/parity/expected/webhook__verification_completed_sparse_result.json new file mode 100644 index 0000000..51c0452 --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_completed_sparse_result.json @@ -0,0 +1,48 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T11:07:00.123456+00:00", + "event": "verification.completed", + "result": { + "audit": { + "adjudication_summary": "", + "assessments": [], + "debate_con": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "debate_pro": { + "argument": "", + "rebuttal": "", + "role": "" + }, + "panel_agreement": "" + }, + "claim": "The Eiffel Tower is in Berlin.", + "confidence": "low", + "coverage": null, + "created_at": "", + "depth": "standard", + "domain": "", + "entities": [], + "executive_summary": "", + "key_finding": "", + "language": "en", + "lenz_score": null, + "modified_at": null, + "presumed_intent": "", + "sources": [], + "suggested_rewrite": null, + "verdict": "", + "verification_id": "68ca4aaf", + "visibility": "private", + "warnings": [] + }, + "status": "completed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "type": "VerificationCompleted", + "verification_id": "68ca4aaf" + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_failed_error_none.json b/tests/fixtures/parity/expected/webhook__verification_failed_error_none.json new file mode 100644 index 0000000..3081f2a --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_failed_error_none.json @@ -0,0 +1,15 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T11:07:00.123456+00:00", + "error": "", + "event": "verification.failed", + "failure_class": "internal", + "retryable": false, + "status": "failed", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "type": "VerificationFailed", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_failed_insufficient_evidence.json b/tests/fixtures/parity/expected/webhook__verification_failed_insufficient_evidence.json index 81bf11e..f455192 100644 --- a/tests/fixtures/parity/expected/webhook__verification_failed_insufficient_evidence.json +++ b/tests/fixtures/parity/expected/webhook__verification_failed_insufficient_evidence.json @@ -2,7 +2,7 @@ "event": { "attempt": 1, "batch_id": null, - "delivered_at": "2026-10-01T09:14:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "error": "research_insufficient", "event": "verification.failed", "failure_class": "insufficient_evidence", diff --git a/tests/fixtures/parity/expected/webhook__verification_failed_not_a_claim.json b/tests/fixtures/parity/expected/webhook__verification_failed_not_a_claim.json index 15e827d..97484e4 100644 --- a/tests/fixtures/parity/expected/webhook__verification_failed_not_a_claim.json +++ b/tests/fixtures/parity/expected/webhook__verification_failed_not_a_claim.json @@ -2,7 +2,7 @@ "event": { "attempt": 1, "batch_id": null, - "delivered_at": "2026-10-01T09:14:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "error": "not_a_claim", "event": "verification.failed", "failure_class": "invalid_input", diff --git a/tests/fixtures/parity/expected/webhook__verification_failed_upstream_unavailable.json b/tests/fixtures/parity/expected/webhook__verification_failed_upstream_unavailable.json index 6ec1bcb..cc5caa7 100644 --- a/tests/fixtures/parity/expected/webhook__verification_failed_upstream_unavailable.json +++ b/tests/fixtures/parity/expected/webhook__verification_failed_upstream_unavailable.json @@ -2,7 +2,7 @@ "event": { "attempt": 1, "batch_id": null, - "delivered_at": "2026-10-01T09:14:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "error": "framing_failed", "event": "verification.failed", "failure_class": "upstream_unavailable", diff --git a/tests/fixtures/parity/expected/webhook__verification_needs_input_hint_none.json b/tests/fixtures/parity/expected/webhook__verification_needs_input_hint_none.json new file mode 100644 index 0000000..93f162e --- /dev/null +++ b/tests/fixtures/parity/expected/webhook__verification_needs_input_hint_none.json @@ -0,0 +1,23 @@ +{ + "event": { + "attempt": 1, + "batch_id": null, + "delivered_at": "2026-10-01T11:07:00.123456+00:00", + "event": "verification.needs_input", + "hint": "", + "needs_input": { + "claims": [ + { + "domain": "", + "text": "The Eiffel Tower is in Berlin." + } + ], + "hint": null, + "reason": "multi_claim" + }, + "status": "needs_input", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "type": "VerificationNeedsInput", + "verification_id": null + } +} diff --git a/tests/fixtures/parity/expected/webhook__verification_needs_input_multi_claim.json b/tests/fixtures/parity/expected/webhook__verification_needs_input_multi_claim.json index 55e2dc8..3a2f006 100644 --- a/tests/fixtures/parity/expected/webhook__verification_needs_input_multi_claim.json +++ b/tests/fixtures/parity/expected/webhook__verification_needs_input_multi_claim.json @@ -2,7 +2,7 @@ "event": { "attempt": 1, "batch_id": null, - "delivered_at": "2026-10-01T09:14:00.123456+00:00", + "delivered_at": "2026-10-01T11:07:00.123456+00:00", "event": "verification.needs_input", "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select.", "needs_input": { diff --git a/tests/fixtures/parity/legacy/account__api_root.json b/tests/fixtures/parity/legacy/account__api_root.json new file mode 100644 index 0000000..592cd14 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__api_root.json @@ -0,0 +1,43 @@ +{ + "status": 200, + "body": { + "name": "Lenz Public API", + "version": "v1", + "docs_url": "https://lenz.io/api/v1/docs/", + "openapi_url": "https://lenz.io/api/v1/openapi.json", + "quickstart_url": "https://lenz.io/docs/quickstart", + "developer_portal_url": "https://lenz.io/developers", + "endpoints": { + "extract": "https://lenz.io/api/v1/extract", + "assess": "https://lenz.io/api/v1/assess", + "verify": "https://lenz.io/api/v1/verify", + "ask": "https://lenz.io/api/v1/ask/{verification_id}", + "verify_status": "https://lenz.io/api/v1/verify/status/{task_id}", + "verifications": "https://lenz.io/api/v1/verifications/{verification_id}", + "library": "https://lenz.io/api/v1/library", + "usage": "https://lenz.io/api/v1/me/usage" + }, + "sdks": { + "python": { + "repository": "https://github.com/lenzhq/lenz-io-python", + "package": "https://pypi.org/project/lenz-io/", + "install": "pip install lenz-io" + }, + "node": { + "repository": "https://github.com/lenzhq/lenz-io-node", + "package": "https://www.npmjs.com/package/lenz-io", + "install": "npm install lenz-io" + } + }, + "mcp": { + "url": "https://lenz.io/mcp", + "transport": "streamable-http", + "repository": "https://github.com/lenzhq/lenz-mcp" + } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__ask_history_after_reset.json b/tests/fixtures/parity/legacy/account__ask_history_after_reset.json new file mode 100644 index 0000000..e9962b2 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__ask_history_after_reset.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "body": { + "messages": [], + "exchanges_used": 0, + "exchange_limit": 100, + "can_send": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__ask_history_after_send.json b/tests/fixtures/parity/legacy/account__ask_history_after_send.json new file mode 100644 index 0000000..ded388d --- /dev/null +++ b/tests/fixtures/parity/legacy/account__ask_history_after_send.json @@ -0,0 +1,25 @@ +{ + "status": 200, + "body": { + "messages": [ + { + "role": "user", + "content": "Why?", + "created_at": "2026-10-01T09:07:00.123456+00:00" + }, + { + "role": "expert", + "content": "Because **evidence**.", + "created_at": "2026-10-01T09:14:00.123456+00:00" + } + ], + "exchanges_used": 1, + "exchange_limit": 100, + "can_send": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__ask_history_empty.json b/tests/fixtures/parity/legacy/account__ask_history_empty.json new file mode 100644 index 0000000..e9962b2 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__ask_history_empty.json @@ -0,0 +1,14 @@ +{ + "status": 200, + "body": { + "messages": [], + "exchanges_used": 0, + "exchange_limit": 100, + "can_send": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__ask_history_messages.json b/tests/fixtures/parity/legacy/account__ask_history_messages.json new file mode 100644 index 0000000..efc4809 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__ask_history_messages.json @@ -0,0 +1,25 @@ +{ + "status": 200, + "body": { + "messages": [ + { + "role": "user", + "content": "Hello", + "created_at": "2026-10-01T09:07:00.123456+00:00" + }, + { + "role": "expert", + "content": "Hi there!", + "created_at": "2026-10-01T09:14:00.123456+00:00" + } + ], + "exchanges_used": 0, + "exchange_limit": 100, + "can_send": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__ask_reset.json b/tests/fixtures/parity/legacy/account__ask_reset.json new file mode 100644 index 0000000..cddadae --- /dev/null +++ b/tests/fixtures/parity/legacy/account__ask_reset.json @@ -0,0 +1,11 @@ +{ + "status": 200, + "body": { + "ok": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__ask_send.json b/tests/fixtures/parity/legacy/account__ask_send.json new file mode 100644 index 0000000..d07ac92 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__ask_send.json @@ -0,0 +1,13 @@ +{ + "status": 200, + "body": { + "role": "expert", + "content": "Because **evidence**.", + "created_at": "2026-10-01T09:07:00.123456+00:00" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__ask_send_language.json b/tests/fixtures/parity/legacy/account__ask_send_language.json new file mode 100644 index 0000000..37c151c --- /dev/null +++ b/tests/fixtures/parity/legacy/account__ask_send_language.json @@ -0,0 +1,13 @@ +{ + "status": 200, + "body": { + "role": "expert", + "content": "Porque.", + "created_at": "2026-10-01T09:07:00.123456+00:00" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__library_empty.json b/tests/fixtures/parity/legacy/account__library_empty.json index b419316..406be8e 100644 --- a/tests/fixtures/parity/legacy/account__library_empty.json +++ b/tests/fixtures/parity/legacy/account__library_empty.json @@ -1,14 +1,14 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [], "total": 0, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__library_item_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/account__library_item_modified_at_crosses_midnight_by_minutes.json index e59c0d7..4e168ad 100644 --- a/tests/fixtures/parity/legacy/account__library_item_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/legacy/account__library_item_modified_at_crosses_midnight_by_minutes.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -26,5 +21,10 @@ "total": 1, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__library_item_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/account__library_item_modified_at_same_day_hours_apart.json index 5fb5763..43ecdcc 100644 --- a/tests/fixtures/parity/legacy/account__library_item_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/legacy/account__library_item_modified_at_same_day_hours_apart.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -26,5 +21,10 @@ "total": 1, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__library_items.json b/tests/fixtures/parity/legacy/account__library_items.json index 2868a2e..a78c2b7 100644 --- a/tests/fixtures/parity/legacy/account__library_items.json +++ b/tests/fixtures/parity/legacy/account__library_items.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -18,12 +13,12 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "language": "en" }, { - "verification_id": "7c83247c", + "verification_id": "4d44dfaf", "claim": "Library claim 1.", "domain": "Science", "entities": [], @@ -33,12 +28,12 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "modified_at": null, "language": "en" }, { - "verification_id": "b79019e4", + "verification_id": "7c83247c", "claim": "Library claim 2.", "domain": "Science", "entities": [], @@ -48,7 +43,7 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:42:00.123456+00:00", + "created_at": "2026-10-01T09:21:00.123456+00:00", "modified_at": null, "language": "en" } @@ -56,5 +51,10 @@ "total": 3, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__library_no_match.json b/tests/fixtures/parity/legacy/account__library_no_match.json index b419316..406be8e 100644 --- a/tests/fixtures/parity/legacy/account__library_no_match.json +++ b/tests/fixtures/parity/legacy/account__library_no_match.json @@ -1,14 +1,14 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [], "total": 0, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__library_page_past_end.json b/tests/fixtures/parity/legacy/account__library_page_past_end.json index 86d64c7..575d59b 100644 --- a/tests/fixtures/parity/legacy/account__library_page_past_end.json +++ b/tests/fixtures/parity/legacy/account__library_page_past_end.json @@ -1,14 +1,14 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [], "total": 1, "page": 2, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__library_paginated_second_page.json b/tests/fixtures/parity/legacy/account__library_paginated_second_page.json index 9529811..67e00eb 100644 --- a/tests/fixtures/parity/legacy/account__library_paginated_second_page.json +++ b/tests/fixtures/parity/legacy/account__library_paginated_second_page.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -18,12 +13,12 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "language": "en" }, { - "verification_id": "7c83247c", + "verification_id": "4d44dfaf", "claim": "Paged claim 021.", "domain": "", "entities": [], @@ -33,7 +28,7 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "modified_at": null, "language": "en" } @@ -41,5 +36,10 @@ "total": 22, "page": 2, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__me_usage_extra_credits.json b/tests/fixtures/parity/legacy/account__me_usage_extra_credits.json index e07e31f..8eb83cf 100644 --- a/tests/fixtures/parity/legacy/account__me_usage_extra_credits.json +++ b/tests/fixtures/parity/legacy/account__me_usage_extra_credits.json @@ -1,21 +1,16 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "credits": { "total": 350, "used": 0, "remaining": 350, "extra": 250, "bonus": 250, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -62,5 +57,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__me_usage_extra_only.json b/tests/fixtures/parity/legacy/account__me_usage_extra_only.json index 0e00cac..5941290 100644 --- a/tests/fixtures/parity/legacy/account__me_usage_extra_only.json +++ b/tests/fixtures/parity/legacy/account__me_usage_extra_only.json @@ -1,21 +1,16 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "credits": { "total": 137, "used": 100, "remaining": 37, "extra": 37, "bonus": 37, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -62,5 +57,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__me_usage_extract_calls.json b/tests/fixtures/parity/legacy/account__me_usage_extract_calls.json index 335d0f1..8ed7b3c 100644 --- a/tests/fixtures/parity/legacy/account__me_usage_extract_calls.json +++ b/tests/fixtures/parity/legacy/account__me_usage_extract_calls.json @@ -1,21 +1,16 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "credits": { "total": 100, "used": 0, "remaining": 100, "extra": 0, "bonus": 0, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -62,5 +57,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__me_usage_free.json b/tests/fixtures/parity/legacy/account__me_usage_free.json index 6a23d7a..5edd565 100644 --- a/tests/fixtures/parity/legacy/account__me_usage_free.json +++ b/tests/fixtures/parity/legacy/account__me_usage_free.json @@ -1,21 +1,16 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "credits": { "total": 100, "used": 0, "remaining": 100, "extra": 0, "bonus": 0, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -62,5 +57,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__me_usage_free_partly_spent.json b/tests/fixtures/parity/legacy/account__me_usage_free_partly_spent.json index 8f43c97..7ef23a6 100644 --- a/tests/fixtures/parity/legacy/account__me_usage_free_partly_spent.json +++ b/tests/fixtures/parity/legacy/account__me_usage_free_partly_spent.json @@ -1,21 +1,16 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "credits": { "total": 100, "used": 17, "remaining": 83, "extra": 0, "bonus": 0, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -62,5 +57,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__me_usage_oauth.json b/tests/fixtures/parity/legacy/account__me_usage_oauth.json new file mode 100644 index 0000000..5edd565 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__me_usage_oauth.json @@ -0,0 +1,66 @@ +{ + "status": 200, + "body": { + "plan": "free", + "plan_label": "Free", + "quota_resets_at": "2026-10-01T14:07:00+00:00", + "credits": { + "total": 100, + "used": 0, + "remaining": 100, + "extra": 0, + "bonus": 0, + "resets_at": "2026-10-01T14:07:00+00:00" + }, + "costs": { + "verify": 10, + "assess": 1, + "ask": 1, + "citation": 1, + "extract": 0 + }, + "cost_options": { + "verify": { + "depth": { + "standard": 10, + "low": 5 + } + } + }, + "verify": { + "quota_used": 0, + "quota_total": 10, + "quota_remaining": 10, + "bonus": 0, + "credits": 0, + "remaining": 10 + }, + "ask": { + "quota_used": 0, + "quota_total": 100, + "quota_remaining": 100, + "bonus": 0, + "credits": 0, + "remaining": 100 + }, + "assess": { + "quota_used": 0, + "quota_total": 100, + "quota_remaining": 100, + "bonus": 0, + "credits": 0, + "remaining": 100 + }, + "extract": { + "calls_today": 0, + "daily_limit": 1000, + "unlimited": false + }, + "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__me_usage_plus.json b/tests/fixtures/parity/legacy/account__me_usage_plus.json index e49254d..6de7069 100644 --- a/tests/fixtures/parity/legacy/account__me_usage_plus.json +++ b/tests/fixtures/parity/legacy/account__me_usage_plus.json @@ -1,21 +1,16 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "plus", "plan_label": "Plus", - "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "quota_resets_at": "2026-10-01T14:07:00.123456+00:00", "credits": { "total": 500, "used": 0, "remaining": 500, "extra": 0, "bonus": 0, - "resets_at": "2026-10-01T09:07:00.123456+00:00" + "resets_at": "2026-10-01T14:07:00.123456+00:00" }, "costs": { "verify": 10, @@ -62,5 +57,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__me_usage_pro.json b/tests/fixtures/parity/legacy/account__me_usage_pro.json index 4c0fab9..8f14251 100644 --- a/tests/fixtures/parity/legacy/account__me_usage_pro.json +++ b/tests/fixtures/parity/legacy/account__me_usage_pro.json @@ -1,21 +1,16 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "pro", "plan_label": "Pro", - "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "quota_resets_at": "2026-10-01T14:07:00.123456+00:00", "credits": { "total": 5000, "used": 0, "remaining": 5000, "extra": 0, "bonus": 0, - "resets_at": "2026-10-01T09:07:00.123456+00:00" + "resets_at": "2026-10-01T14:07:00.123456+00:00" }, "costs": { "verify": 10, @@ -62,5 +57,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__me_usage_pro_extra.json b/tests/fixtures/parity/legacy/account__me_usage_pro_extra.json index a15d613..fe0a019 100644 --- a/tests/fixtures/parity/legacy/account__me_usage_pro_extra.json +++ b/tests/fixtures/parity/legacy/account__me_usage_pro_extra.json @@ -1,21 +1,16 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "pro", "plan_label": "Pro", - "quota_resets_at": "2026-10-01T09:07:00.123456+00:00", + "quota_resets_at": "2026-10-01T14:07:00.123456+00:00", "credits": { "total": 6000, "used": 0, "remaining": 6000, "extra": 1000, "bonus": 1000, - "resets_at": "2026-10-01T09:07:00.123456+00:00" + "resets_at": "2026-10-01T14:07:00.123456+00:00" }, "costs": { "verify": 10, @@ -62,5 +57,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__me_usage_stale_quota_row.json b/tests/fixtures/parity/legacy/account__me_usage_stale_quota_row.json index 6a23d7a..5edd565 100644 --- a/tests/fixtures/parity/legacy/account__me_usage_stale_quota_row.json +++ b/tests/fixtures/parity/legacy/account__me_usage_stale_quota_row.json @@ -1,21 +1,16 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "plan": "free", "plan_label": "Free", - "quota_resets_at": "2026-10-01T09:07:00+00:00", + "quota_resets_at": "2026-10-01T14:07:00+00:00", "credits": { "total": 100, "used": 0, "remaining": 100, "extra": 0, "bonus": 0, - "resets_at": "2026-10-01T09:07:00+00:00" + "resets_at": "2026-10-01T14:07:00+00:00" }, "costs": { "verify": 10, @@ -62,5 +57,10 @@ "unlimited": false }, "has_webhook_secret": false + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/account__oauth_register_success.json b/tests/fixtures/parity/legacy/account__oauth_register_success.json new file mode 100644 index 0000000..15e9752 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__oauth_register_success.json @@ -0,0 +1,25 @@ +{ + "status": 201, + "body": { + "client_id": "lzc_0a1db81dbba84d2d473826d8", + "client_id_issued_at": "", + "client_name": "n8n", + "redirect_uris": [ + "https://acme.app.n8n.cloud/rest/oauth2-credential/callback" + ], + "grant_types": [ + "authorization_code", + "refresh_token" + ], + "response_types": [ + "code" + ], + "token_endpoint_auth_method": "none", + "scope": "assess verify ask ask:read extract history:read history:write usage:read webhooks:manage" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__oauth_revoke.json b/tests/fixtures/parity/legacy/account__oauth_revoke.json new file mode 100644 index 0000000..f0ea1e6 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__oauth_revoke.json @@ -0,0 +1,9 @@ +{ + "status": 200, + "body": {}, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__oauth_revoke_token.json b/tests/fixtures/parity/legacy/account__oauth_revoke_token.json new file mode 100644 index 0000000..f0ea1e6 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__oauth_revoke_token.json @@ -0,0 +1,9 @@ +{ + "status": 200, + "body": {}, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__webhook_secret_api_key.json b/tests/fixtures/parity/legacy/account__webhook_secret_api_key.json new file mode 100644 index 0000000..4fdb761 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__webhook_secret_api_key.json @@ -0,0 +1,12 @@ +{ + "status": 403, + "body": { + "detail": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.", + "code": "oauth_only" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__webhook_secret_insufficient_scope.json b/tests/fixtures/parity/legacy/account__webhook_secret_insufficient_scope.json new file mode 100644 index 0000000..6e2d697 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__webhook_secret_insufficient_scope.json @@ -0,0 +1,14 @@ +{ + "status": 403, + "body": { + "detail": "The access token does not allow this call.", + "code": "insufficient_scope", + "scope": "webhooks:manage" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "WWW-Authenticate": "Bearer error=\"insufficient_scope\", scope=\"webhooks:manage\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/account__webhook_secret_oauth.json b/tests/fixtures/parity/legacy/account__webhook_secret_oauth.json new file mode 100644 index 0000000..65ec897 --- /dev/null +++ b/tests/fixtures/parity/legacy/account__webhook_secret_oauth.json @@ -0,0 +1,11 @@ +{ + "status": 200, + "body": { + "webhook_secret": "dc06a4fb5512d77eb96f64eedf3ce77dff58de30e17140fbb229a3e048c3bb93" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/assess__401_no_key.json b/tests/fixtures/parity/legacy/assess__401_no_key.json index 8dd2fb4..54ec0b6 100644 --- a/tests/fixtures/parity/legacy/assess__401_no_key.json +++ b/tests/fixtures/parity/legacy/assess__401_no_key.json @@ -1,11 +1,11 @@ { "status": 401, + "body": { + "detail": "Unauthorized" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized" } } diff --git a/tests/fixtures/parity/legacy/assess__402_no_credits.json b/tests/fixtures/parity/legacy/assess__402_no_credits.json index 1cd3038..50f67b4 100644 --- a/tests/fixtures/parity/legacy/assess__402_no_credits.json +++ b/tests/fixtures/parity/legacy/assess__402_no_credits.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining /assess units.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__422_blank_item.json b/tests/fixtures/parity/legacy/assess__422_blank_item.json index af5a22a..94cac74 100644 --- a/tests/fixtures/parity/legacy/assess__422_blank_item.json +++ b/tests/fixtures/parity/legacy/assess__422_blank_item.json @@ -1,12 +1,12 @@ { "status": 422, + "body": { + "detail": "claims[1] is blank.", + "code": "blank_item" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "claims[1] is blank.", - "code": "blank_item" } } diff --git a/tests/fixtures/parity/legacy/assess__422_blank_text.json b/tests/fixtures/parity/legacy/assess__422_blank_text.json index 1ebb88e..367f620 100644 --- a/tests/fixtures/parity/legacy/assess__422_blank_text.json +++ b/tests/fixtures/parity/legacy/assess__422_blank_text.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Text is required." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Text is required." } } diff --git a/tests/fixtures/parity/legacy/assess__422_input_conflict.json b/tests/fixtures/parity/legacy/assess__422_input_conflict.json index c811d89..5f709c8 100644 --- a/tests/fixtures/parity/legacy/assess__422_input_conflict.json +++ b/tests/fixtures/parity/legacy/assess__422_input_conflict.json @@ -1,12 +1,12 @@ { "status": 422, + "body": { + "detail": "Send either `claim` (one text) or `claims` (a list of claims), not both.", + "code": "input_conflict" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Send either `claim` (one text) or `claims` (a list of claims), not both.", - "code": "input_conflict" } } diff --git a/tests/fixtures/parity/legacy/assess__422_item_too_long.json b/tests/fixtures/parity/legacy/assess__422_item_too_long.json index 21e6f19..34cbc4d 100644 --- a/tests/fixtures/parity/legacy/assess__422_item_too_long.json +++ b/tests/fixtures/parity/legacy/assess__422_item_too_long.json @@ -1,12 +1,12 @@ { "status": 422, + "body": { + "detail": "claims[1] is 2001 characters; each claim may be at most 2000. Send a document to /extract first, then assess its claims.", + "code": "item_too_long" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "claims[1] is 2001 characters; each claim may be at most 2000. Send a document to /extract first, then assess its claims.", - "code": "item_too_long" } } diff --git a/tests/fixtures/parity/legacy/assess__422_no_input_field.json b/tests/fixtures/parity/legacy/assess__422_no_input_field.json index f862968..591c22f 100644 --- a/tests/fixtures/parity/legacy/assess__422_no_input_field.json +++ b/tests/fixtures/parity/legacy/assess__422_no_input_field.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -17,5 +12,10 @@ "msg": "Field required" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__422_too_many_items.json b/tests/fixtures/parity/legacy/assess__422_too_many_items.json index 80d556a..4c88204 100644 --- a/tests/fixtures/parity/legacy/assess__422_too_many_items.json +++ b/tests/fixtures/parity/legacy/assess__422_too_many_items.json @@ -1,12 +1,12 @@ { "status": 422, + "body": { + "detail": "At most 20 claims per call; got 21. Split the list.", + "code": "too_many_items" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "At most 20 claims per call; got 21. Split the list.", - "code": "too_many_items" } } diff --git a/tests/fixtures/parity/legacy/assess__422_wrong_type_claim.json b/tests/fixtures/parity/legacy/assess__422_wrong_type_claim.json index d8d8c87..dd070e7 100644 --- a/tests/fixtures/parity/legacy/assess__422_wrong_type_claim.json +++ b/tests/fixtures/parity/legacy/assess__422_wrong_type_claim.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -17,5 +12,10 @@ "msg": "Input should be a valid string" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__422_wrong_type_claims.json b/tests/fixtures/parity/legacy/assess__422_wrong_type_claims.json index a997f8c..0a135da 100644 --- a/tests/fixtures/parity/legacy/assess__422_wrong_type_claims.json +++ b/tests/fixtures/parity/legacy/assess__422_wrong_type_claims.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -17,5 +12,10 @@ "msg": "Input should be a valid list" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__502_framing_failed.json b/tests/fixtures/parity/legacy/assess__502_framing_failed.json index 9b6d047..a15f201 100644 --- a/tests/fixtures/parity/legacy/assess__502_framing_failed.json +++ b/tests/fixtures/parity/legacy/assess__502_framing_failed.json @@ -1,13 +1,13 @@ { "status": 502, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Framing failed", "code": "framing_failed", "error": "framing_failed" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__503_capacity.json b/tests/fixtures/parity/legacy/assess__503_capacity.json index de01494..4c5b2c2 100644 --- a/tests/fixtures/parity/legacy/assess__503_capacity.json +++ b/tests/fixtures/parity/legacy/assess__503_capacity.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "100", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": 100, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "100", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__503_list_all_upstream_unavailable.json b/tests/fixtures/parity/legacy/assess__503_list_all_upstream_unavailable.json index 9e74dd2..d37b434 100644 --- a/tests/fixtures/parity/legacy/assess__503_list_all_upstream_unavailable.json +++ b/tests/fixtures/parity/legacy/assess__503_list_all_upstream_unavailable.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Our model providers are temporarily unavailable. Please retry shortly. Nothing was charged.", "code": "upstream_unavailable", "retry_after": 90, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__503_upstream_unavailable.json b/tests/fixtures/parity/legacy/assess__503_upstream_unavailable.json index b308e0c..9308b85 100644 --- a/tests/fixtures/parity/legacy/assess__503_upstream_unavailable.json +++ b/tests/fixtures/parity/legacy/assess__503_upstream_unavailable.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Our model providers are temporarily unavailable. Please retry shortly.", "code": "upstream_unavailable", "retry_after": 90, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__deep_tier_hit.json b/tests/fixtures/parity/legacy/assess__deep_tier_hit.json index a5e696a..ec51c5f 100644 --- a/tests/fixtures/parity/legacy/assess__deep_tier_hit.json +++ b/tests/fixtures/parity/legacy/assess__deep_tier_hit.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -24,5 +19,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__idempotency_body_mismatch.json b/tests/fixtures/parity/legacy/assess__idempotency_body_mismatch.json index ef04562..2425649 100644 --- a/tests/fixtures/parity/legacy/assess__idempotency_body_mismatch.json +++ b/tests/fixtures/parity/legacy/assess__idempotency_body_mismatch.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Idempotency-Key reused with a different request body." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Idempotency-Key reused with a different request body." } } diff --git a/tests/fixtures/parity/legacy/assess__idempotency_first.json b/tests/fixtures/parity/legacy/assess__idempotency_first.json index bac5c15..fedc9c5 100644 --- a/tests/fixtures/parity/legacy/assess__idempotency_first.json +++ b/tests/fixtures/parity/legacy/assess__idempotency_first.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -24,5 +19,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__idempotency_replay.json b/tests/fixtures/parity/legacy/assess__idempotency_replay.json index bac5c15..fedc9c5 100644 --- a/tests/fixtures/parity/legacy/assess__idempotency_replay.json +++ b/tests/fixtures/parity/legacy/assess__idempotency_replay.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -24,5 +19,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__list_all_error_rows.json b/tests/fixtures/parity/legacy/assess__list_all_error_rows.json index ba846f5..d376f1f 100644 --- a/tests/fixtures/parity/legacy/assess__list_all_error_rows.json +++ b/tests/fixtures/parity/legacy/assess__list_all_error_rows.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -38,5 +33,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__list_compound_item.json b/tests/fixtures/parity/legacy/assess__list_compound_item.json index 2a9d928..cc02da1 100644 --- a/tests/fixtures/parity/legacy/assess__list_compound_item.json +++ b/tests/fixtures/parity/legacy/assess__list_compound_item.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -41,5 +36,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__list_mixed_rows.json b/tests/fixtures/parity/legacy/assess__list_mixed_rows.json index 5c4bfe1..2143d2d 100644 --- a/tests/fixtures/parity/legacy/assess__list_mixed_rows.json +++ b/tests/fixtures/parity/legacy/assess__list_mixed_rows.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -66,5 +61,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__memo_hit.json b/tests/fixtures/parity/legacy/assess__memo_hit.json index 96a0c4d..895b4d1 100644 --- a/tests/fixtures/parity/legacy/assess__memo_hit.json +++ b/tests/fixtures/parity/legacy/assess__memo_hit.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -24,5 +19,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__replay_later_200.json b/tests/fixtures/parity/legacy/assess__replay_later_200.json index bac5c15..fedc9c5 100644 --- a/tests/fixtures/parity/legacy/assess__replay_later_200.json +++ b/tests/fixtures/parity/legacy/assess__replay_later_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -24,5 +19,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__single_no_claim.json b/tests/fixtures/parity/legacy/assess__single_no_claim.json index b40abf7..30e6d5f 100644 --- a/tests/fixtures/parity/legacy/assess__single_no_claim.json +++ b/tests/fixtures/parity/legacy/assess__single_no_claim.json @@ -1,15 +1,15 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [], "error": "No verifiable claim detected", "error_code": "no_claim", "candidate_claims": [], "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__single_one_claim.json b/tests/fixtures/parity/legacy/assess__single_one_claim.json index d27e7eb..329438b 100644 --- a/tests/fixtures/parity/legacy/assess__single_one_claim.json +++ b/tests/fixtures/parity/legacy/assess__single_one_claim.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -24,5 +19,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__single_text_over_wave_more_claims.json b/tests/fixtures/parity/legacy/assess__single_text_over_wave_more_claims.json index d4849fc..fdc4751 100644 --- a/tests/fixtures/parity/legacy/assess__single_text_over_wave_more_claims.json +++ b/tests/fixtures/parity/legacy/assess__single_text_over_wave_more_claims.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -293,5 +288,10 @@ "Claim number 20 is documented.", "Claim number 21 is documented." ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__single_text_several_claims.json b/tests/fixtures/parity/legacy/assess__single_text_several_claims.json index 2db91ed..ffce99c 100644 --- a/tests/fixtures/parity/legacy/assess__single_text_several_claims.json +++ b/tests/fixtures/parity/legacy/assess__single_text_several_claims.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -52,5 +47,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/assess__suggest_rewrite.json b/tests/fixtures/parity/legacy/assess__suggest_rewrite.json index f4f7b54..68f4fa2 100644 --- a/tests/fixtures/parity/legacy/assess__suggest_rewrite.json +++ b/tests/fixtures/parity/legacy/assess__suggest_rewrite.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "claims": [ { @@ -38,5 +33,10 @@ ], "error": null, "more_claims": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__402_no_credits.json b/tests/fixtures/parity/legacy/citecheck__402_no_credits.json index 200f42b..a73ca33 100644 --- a/tests/fixtures/parity/legacy/citecheck__402_no_credits.json +++ b/tests/fixtures/parity/legacy/citecheck__402_no_credits.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining credits for citation checks.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 100, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 100, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_empty_body.json b/tests/fixtures/parity/legacy/citecheck__422_empty_body.json index 6f9d742..8fde0be 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_empty_body.json +++ b/tests/fixtures/parity/legacy/citecheck__422_empty_body.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload: Value error, send exactly one of text and pairs", "code": "validation_error", @@ -17,5 +12,10 @@ "msg": "Value error, send exactly one of text and pairs" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_invalid_doi.json b/tests/fixtures/parity/legacy/citecheck__422_invalid_doi.json index 3026138..7177677 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_invalid_doi.json +++ b/tests/fixtures/parity/legacy/citecheck__422_invalid_doi.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.pairs.0.doi: Send the DOI alone, like 10.1038/nature12373.", "code": "invalid_doi", @@ -20,5 +15,10 @@ "msg": "Send the DOI alone, like 10.1038/nature12373." } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_max_citations_over_20.json b/tests/fixtures/parity/legacy/citecheck__422_max_citations_over_20.json index 279eba0..710466e 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_max_citations_over_20.json +++ b/tests/fixtures/parity/legacy/citecheck__422_max_citations_over_20.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.max_citations: Input should be less than or equal to 20", "code": "validation_error", @@ -18,5 +13,10 @@ "msg": "Input should be less than or equal to 20" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_max_citations_with_pairs.json b/tests/fixtures/parity/legacy/citecheck__422_max_citations_with_pairs.json index bd0828b..218964a 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_max_citations_with_pairs.json +++ b/tests/fixtures/parity/legacy/citecheck__422_max_citations_with_pairs.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload: Value error, max_citations goes with text: every pair is checked", "code": "validation_error", @@ -17,5 +12,10 @@ "msg": "Value error, max_citations goes with text: every pair is checked" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_pair_bad_url_scheme.json b/tests/fixtures/parity/legacy/citecheck__422_pair_bad_url_scheme.json index c7046cc..b557fbf 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_pair_bad_url_scheme.json +++ b/tests/fixtures/parity/legacy/citecheck__422_pair_bad_url_scheme.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.pairs.0.url: Value error, url: an http or https link", "code": "validation_error", @@ -20,5 +15,10 @@ "msg": "Value error, url: an http or https link" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_pair_no_source.json b/tests/fixtures/parity/legacy/citecheck__422_pair_no_source.json index 10ddcdb..0619ab6 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_pair_no_source.json +++ b/tests/fixtures/parity/legacy/citecheck__422_pair_no_source.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.pairs.0: Value error, send exactly one of url and doi", "code": "validation_error", @@ -19,5 +14,10 @@ "msg": "Value error, send exactly one of url and doi" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_pair_url_and_doi.json b/tests/fixtures/parity/legacy/citecheck__422_pair_url_and_doi.json index 10ddcdb..0619ab6 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_pair_url_and_doi.json +++ b/tests/fixtures/parity/legacy/citecheck__422_pair_url_and_doi.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.pairs.0: Value error, send exactly one of url and doi", "code": "validation_error", @@ -19,5 +14,10 @@ "msg": "Value error, send exactly one of url and doi" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_pairs_empty.json b/tests/fixtures/parity/legacy/citecheck__422_pairs_empty.json index 2df0724..edc2537 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_pairs_empty.json +++ b/tests/fixtures/parity/legacy/citecheck__422_pairs_empty.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.pairs: Value error, pairs: 1 to 20 items", "code": "validation_error", @@ -18,5 +13,10 @@ "msg": "Value error, pairs: 1 to 20 items" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_pairs_over_20.json b/tests/fixtures/parity/legacy/citecheck__422_pairs_over_20.json index 2df0724..edc2537 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_pairs_over_20.json +++ b/tests/fixtures/parity/legacy/citecheck__422_pairs_over_20.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.pairs: Value error, pairs: 1 to 20 items", "code": "validation_error", @@ -18,5 +13,10 @@ "msg": "Value error, pairs: 1 to 20 items" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_quote_not_in_statement.json b/tests/fixtures/parity/legacy/citecheck__422_quote_not_in_statement.json index 462190c..9c4f0a3 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_quote_not_in_statement.json +++ b/tests/fixtures/parity/legacy/citecheck__422_quote_not_in_statement.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.pairs.0: Each quote must be words of its statement.", "code": "quote_not_in_statement", @@ -19,5 +14,10 @@ "msg": "Each quote must be words of its statement." } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_text_and_pairs.json b/tests/fixtures/parity/legacy/citecheck__422_text_and_pairs.json index 6f9d742..8fde0be 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_text_and_pairs.json +++ b/tests/fixtures/parity/legacy/citecheck__422_text_and_pairs.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload: Value error, send exactly one of text and pairs", "code": "validation_error", @@ -17,5 +12,10 @@ "msg": "Value error, send exactly one of text and pairs" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_unknown_field.json b/tests/fixtures/parity/legacy/citecheck__422_unknown_field.json index cb50c65..b63a6d8 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_unknown_field.json +++ b/tests/fixtures/parity/legacy/citecheck__422_unknown_field.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.pairs.0.extra: Extra inputs are not permitted", "code": "validation_error", @@ -20,5 +15,10 @@ "msg": "Extra inputs are not permitted" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_url_input.json b/tests/fixtures/parity/legacy/citecheck__422_url_input.json index d5ddd25..c6786a8 100644 --- a/tests/fixtures/parity/legacy/citecheck__422_url_input.json +++ b/tests/fixtures/parity/legacy/citecheck__422_url_input.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Send the page's text, with its links, to check the sources it cites.", "code": "url_input", @@ -17,5 +12,10 @@ "msg": "Send the page's text, with its links, to check the sources it cites." } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__422_webhook_secret_missing.json b/tests/fixtures/parity/legacy/citecheck__422_webhook_secret_missing.json new file mode 100644 index 0000000..1ecf2d1 --- /dev/null +++ b/tests/fixtures/parity/legacy/citecheck__422_webhook_secret_missing.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "body": { + "detail": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "code": "webhook_secret_missing", + "errors": [ + { + "loc": [ + "body", + "webhook_url" + ], + "msg": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend." + } + ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/citecheck__429_citecheck_in_flight.json b/tests/fixtures/parity/legacy/citecheck__429_citecheck_in_flight.json index 5222210..5ae869f 100644 --- a/tests/fixtures/parity/legacy/citecheck__429_citecheck_in_flight.json +++ b/tests/fixtures/parity/legacy/citecheck__429_citecheck_in_flight.json @@ -1,14 +1,14 @@ { "status": 429, + "body": { + "detail": "This account already has 3 citation checks running. Wait for one to finish.", + "code": "citecheck_in_flight", + "retry_after_seconds": 60 + }, "headers": { "Content-Type": "application/json", "Retry-After": "60", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "This account already has 3 citation checks running. Wait for one to finish.", - "code": "citecheck_in_flight", - "retry_after_seconds": 60 } } diff --git a/tests/fixtures/parity/legacy/citecheck__503_capacity.json b/tests/fixtures/parity/legacy/citecheck__503_capacity.json index adcc209..085990c 100644 --- a/tests/fixtures/parity/legacy/citecheck__503_capacity.json +++ b/tests/fixtures/parity/legacy/citecheck__503_capacity.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": 90, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__503_citations_unavailable.json b/tests/fixtures/parity/legacy/citecheck__503_citations_unavailable.json index ea4e7b8..3be14e4 100644 --- a/tests/fixtures/parity/legacy/citecheck__503_citations_unavailable.json +++ b/tests/fixtures/parity/legacy/citecheck__503_citations_unavailable.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "300", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Citation checking is switched off right now. Retry later; nothing was charged.", "code": "citations_unavailable", "retry_after": 300, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "300", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_404_not_found.json b/tests/fixtures/parity/legacy/citecheck__get_404_not_found.json index e0adfb3..5aa3709 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_404_not_found.json +++ b/tests/fixtures/parity/legacy/citecheck__get_404_not_found.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Citation check not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Citation check not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_404_review_id.json b/tests/fixtures/parity/legacy/citecheck__get_404_review_id.json index e0adfb3..5aa3709 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_404_review_id.json +++ b/tests/fixtures/parity/legacy/citecheck__get_404_review_id.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Citation check not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Citation check not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_410_purged.json b/tests/fixtures/parity/legacy/citecheck__get_410_purged.json index 9fff981..08b9585 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_410_purged.json +++ b/tests/fixtures/parity/legacy/citecheck__get_410_purged.json @@ -1,13 +1,13 @@ { "status": 410, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This check is no longer available: its account removes content after a set period.", "code": "purged", "purged_at": "2026-10-01T09:07:00.123456Z" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_checking.json b/tests/fixtures/parity/legacy/citecheck__get_checking.json index 3c32986..57a5d80 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_checking.json +++ b/tests/fixtures/parity/legacy/citecheck__get_checking.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "checking", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "poll_after_seconds": 10, @@ -99,5 +94,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_clean.json b/tests/fixtures/parity/legacy/citecheck__get_completed_clean.json index 5e92112..2cb9173 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_completed_clean.json +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_clean.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -107,5 +102,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_doi_pair.json b/tests/fixtures/parity/legacy/citecheck__get_completed_doi_pair.json index 2bdb1bf..bc7c684 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_completed_doi_pair.json +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_doi_pair.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -72,5 +67,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_incomplete.json b/tests/fixtures/parity/legacy/citecheck__get_completed_incomplete.json index 316b4d5..beddca7 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_completed_incomplete.json +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_incomplete.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -123,5 +118,10 @@ ], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_issues_found.json b/tests/fixtures/parity/legacy/citecheck__get_completed_issues_found.json index 75b7f7d..e730c7e 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_completed_issues_found.json +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_issues_found.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -137,5 +132,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_partly_supported.json b/tests/fixtures/parity/legacy/citecheck__get_completed_partly_supported.json index 5ae2366..8f1a891 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_completed_partly_supported.json +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_partly_supported.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -107,5 +102,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_completed_unchecked.json b/tests/fixtures/parity/legacy/citecheck__get_completed_unchecked.json index 4e53bd4..bc4922d 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_completed_unchecked.json +++ b/tests/fixtures/parity/legacy/citecheck__get_completed_unchecked.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -107,5 +102,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_failed_no_citations.json b/tests/fixtures/parity/legacy/citecheck__get_failed_no_citations.json index c66a84e..6a9084b 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_failed_no_citations.json +++ b/tests/fixtures/parity/legacy/citecheck__get_failed_no_citations.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -38,5 +33,10 @@ "docs_url": "https://lenz.io/docs/errors#invalid-input" }, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_failed_upstream_unavailable.json b/tests/fixtures/parity/legacy/citecheck__get_failed_upstream_unavailable.json index 2fba44d..9f29da1 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_failed_upstream_unavailable.json +++ b/tests/fixtures/parity/legacy/citecheck__get_failed_upstream_unavailable.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -144,5 +139,10 @@ "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" }, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_queued.json b/tests/fixtures/parity/legacy/citecheck__get_queued.json index 3e7d4d1..85fbb28 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_queued.json +++ b/tests/fixtures/parity/legacy/citecheck__get_queued.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "queued", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "poll_after_seconds": 10, @@ -68,5 +63,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_text_limit_exactly_at_limit.json b/tests/fixtures/parity/legacy/citecheck__get_text_limit_exactly_at_limit.json index 0ff4ff1..8740719 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_text_limit_exactly_at_limit.json +++ b/tests/fixtures/parity/legacy/citecheck__get_text_limit_exactly_at_limit.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -115,5 +110,10 @@ "citation_failures": [], "failure": null, "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__get_text_limit_reached.json b/tests/fixtures/parity/legacy/citecheck__get_text_limit_reached.json index 764e8b1..c432a1c 100644 --- a/tests/fixtures/parity/legacy/citecheck__get_text_limit_reached.json +++ b/tests/fixtures/parity/legacy/citecheck__get_text_limit_reached.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "citecheck_id": "8eb49302", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -89,5 +84,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__idempotency_body_mismatch_422.json b/tests/fixtures/parity/legacy/citecheck__idempotency_body_mismatch_422.json index fc47586..1c526f0 100644 --- a/tests/fixtures/parity/legacy/citecheck__idempotency_body_mismatch_422.json +++ b/tests/fixtures/parity/legacy/citecheck__idempotency_body_mismatch_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Idempotency-Key reused with a different request body.", "code": "idempotency_body_mismatch", @@ -16,5 +11,10 @@ "msg": "Idempotency-Key reused with a different request body." } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__idempotency_conflict_409.json b/tests/fixtures/parity/legacy/citecheck__idempotency_conflict_409.json index 3978a83..c29d230 100644 --- a/tests/fixtures/parity/legacy/citecheck__idempotency_conflict_409.json +++ b/tests/fixtures/parity/legacy/citecheck__idempotency_conflict_409.json @@ -1,13 +1,13 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "A check with this Idempotency-Key is still being created. Retry shortly.", "code": "idempotency_conflict", "citecheck_id": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/citecheck__idempotent_replay_202.json b/tests/fixtures/parity/legacy/citecheck__idempotent_replay_202.json index 864551e..43d3598 100644 --- a/tests/fixtures/parity/legacy/citecheck__idempotent_replay_202.json +++ b/tests/fixtures/parity/legacy/citecheck__idempotent_replay_202.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/citechecks/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "citecheck_id": "8eb49302", - "status": "queued" } } diff --git a/tests/fixtures/parity/legacy/citecheck__receipt_202.json b/tests/fixtures/parity/legacy/citecheck__receipt_202.json index 864551e..43d3598 100644 --- a/tests/fixtures/parity/legacy/citecheck__receipt_202.json +++ b/tests/fixtures/parity/legacy/citecheck__receipt_202.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/citechecks/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "citecheck_id": "8eb49302", - "status": "queued" } } diff --git a/tests/fixtures/parity/legacy/citecheck__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/legacy/citecheck__receipt_202_empty_webhook_url.json index 864551e..43d3598 100644 --- a/tests/fixtures/parity/legacy/citecheck__receipt_202_empty_webhook_url.json +++ b/tests/fixtures/parity/legacy/citecheck__receipt_202_empty_webhook_url.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "citecheck_id": "8eb49302", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/citechecks/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "citecheck_id": "8eb49302", - "status": "queued" } } diff --git a/tests/fixtures/parity/legacy/errors__ask_bad_language.json b/tests/fixtures/parity/legacy/errors__ask_bad_language.json index 2d6c4b1..ea416f6 100644 --- a/tests/fixtures/parity/legacy/errors__ask_bad_language.json +++ b/tests/fixtures/parity/legacy/errors__ask_bad_language.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Unsupported language 'xx-nope'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unsupported language 'xx-nope'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact." } } diff --git a/tests/fixtures/parity/legacy/errors__ask_empty_message.json b/tests/fixtures/parity/legacy/errors__ask_empty_message.json index 1eee180..5ee6ef6 100644 --- a/tests/fixtures/parity/legacy/errors__ask_empty_message.json +++ b/tests/fixtures/parity/legacy/errors__ask_empty_message.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Message cannot be empty." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Message cannot be empty." } } diff --git a/tests/fixtures/parity/legacy/errors__ask_failed.json b/tests/fixtures/parity/legacy/errors__ask_failed.json index 6eb6b31..f3c8931 100644 --- a/tests/fixtures/parity/legacy/errors__ask_failed.json +++ b/tests/fixtures/parity/legacy/errors__ask_failed.json @@ -1,13 +1,13 @@ { "status": 502, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "The chat model could not answer this question.", "code": "ask_failed", "error": "ask_failed" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__ask_idempotency_key_reused.json b/tests/fixtures/parity/legacy/errors__ask_idempotency_key_reused.json index ef04562..2425649 100644 --- a/tests/fixtures/parity/legacy/errors__ask_idempotency_key_reused.json +++ b/tests/fixtures/parity/legacy/errors__ask_idempotency_key_reused.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Idempotency-Key reused with a different request body." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Idempotency-Key reused with a different request body." } } diff --git a/tests/fixtures/parity/legacy/errors__ask_message_too_long.json b/tests/fixtures/parity/legacy/errors__ask_message_too_long.json index 659caed..3ad27a5 100644 --- a/tests/fixtures/parity/legacy/errors__ask_message_too_long.json +++ b/tests/fixtures/parity/legacy/errors__ask_message_too_long.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Message too long (max 500 characters)." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Message too long (max 500 characters)." } } diff --git a/tests/fixtures/parity/legacy/errors__ask_not_completed.json b/tests/fixtures/parity/legacy/errors__ask_not_completed.json index b59d747..6f7da62 100644 --- a/tests/fixtures/parity/legacy/errors__ask_not_completed.json +++ b/tests/fixtures/parity/legacy/errors__ask_not_completed.json @@ -1,11 +1,11 @@ { "status": 400, + "body": { + "detail": "Ask is only available for completed verifications." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Ask is only available for completed verifications." } } diff --git a/tests/fixtures/parity/legacy/errors__ask_reset_not_found.json b/tests/fixtures/parity/legacy/errors__ask_reset_not_found.json index c0d18e1..65ff442 100644 --- a/tests/fixtures/parity/legacy/errors__ask_reset_not_found.json +++ b/tests/fixtures/parity/legacy/errors__ask_reset_not_found.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "detail": "Verification not found." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Verification not found." } } diff --git a/tests/fixtures/parity/legacy/errors__ask_send_not_found.json b/tests/fixtures/parity/legacy/errors__ask_send_not_found.json index c0d18e1..65ff442 100644 --- a/tests/fixtures/parity/legacy/errors__ask_send_not_found.json +++ b/tests/fixtures/parity/legacy/errors__ask_send_not_found.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "detail": "Verification not found." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Verification not found." } } diff --git a/tests/fixtures/parity/legacy/errors__auth_bad_key.json b/tests/fixtures/parity/legacy/errors__auth_bad_key.json index 8dd2fb4..54ec0b6 100644 --- a/tests/fixtures/parity/legacy/errors__auth_bad_key.json +++ b/tests/fixtures/parity/legacy/errors__auth_bad_key.json @@ -1,11 +1,11 @@ { "status": 401, + "body": { + "detail": "Unauthorized" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized" } } diff --git a/tests/fixtures/parity/legacy/errors__auth_bad_oauth_token.json b/tests/fixtures/parity/legacy/errors__auth_bad_oauth_token.json new file mode 100644 index 0000000..cc8ef29 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_bad_oauth_token.json @@ -0,0 +1,13 @@ +{ + "status": 401, + "body": { + "detail": "The access token is invalid, expired or revoked.", + "code": "invalid_token" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "WWW-Authenticate": "Bearer error=\"invalid_token\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_basic_scheme.json b/tests/fixtures/parity/legacy/errors__auth_basic_scheme.json index 8dd2fb4..54ec0b6 100644 --- a/tests/fixtures/parity/legacy/errors__auth_basic_scheme.json +++ b/tests/fixtures/parity/legacy/errors__auth_basic_scheme.json @@ -1,11 +1,11 @@ { "status": 401, + "body": { + "detail": "Unauthorized" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized" } } diff --git a/tests/fixtures/parity/legacy/errors__auth_expired_oauth_token.json b/tests/fixtures/parity/legacy/errors__auth_expired_oauth_token.json new file mode 100644 index 0000000..cc8ef29 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_expired_oauth_token.json @@ -0,0 +1,13 @@ +{ + "status": 401, + "body": { + "detail": "The access token is invalid, expired or revoked.", + "code": "invalid_token" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "WWW-Authenticate": "Bearer error=\"invalid_token\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_insufficient_scope.json b/tests/fixtures/parity/legacy/errors__auth_insufficient_scope.json index 15b8696..4c2fcdd 100644 --- a/tests/fixtures/parity/legacy/errors__auth_insufficient_scope.json +++ b/tests/fixtures/parity/legacy/errors__auth_insufficient_scope.json @@ -1,14 +1,14 @@ { "status": 403, + "body": { + "detail": "The access token does not allow this call.", + "code": "insufficient_scope", + "scope": "verify" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "WWW-Authenticate": "Bearer error=\"insufficient_scope\", scope=\"verify\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "The access token does not allow this call.", - "code": "insufficient_scope", - "scope": "verify" } } diff --git a/tests/fixtures/parity/legacy/errors__auth_missing_bearer.json b/tests/fixtures/parity/legacy/errors__auth_missing_bearer.json index 8dd2fb4..54ec0b6 100644 --- a/tests/fixtures/parity/legacy/errors__auth_missing_bearer.json +++ b/tests/fixtures/parity/legacy/errors__auth_missing_bearer.json @@ -1,11 +1,11 @@ { "status": 401, + "body": { + "detail": "Unauthorized" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized" } } diff --git a/tests/fixtures/parity/legacy/errors__auth_missing_bearer_post.json b/tests/fixtures/parity/legacy/errors__auth_missing_bearer_post.json index 8dd2fb4..54ec0b6 100644 --- a/tests/fixtures/parity/legacy/errors__auth_missing_bearer_post.json +++ b/tests/fixtures/parity/legacy/errors__auth_missing_bearer_post.json @@ -1,11 +1,11 @@ { "status": 401, + "body": { + "detail": "Unauthorized" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized" } } diff --git a/tests/fixtures/parity/legacy/errors__auth_oauth_issuer_off.json b/tests/fixtures/parity/legacy/errors__auth_oauth_issuer_off.json new file mode 100644 index 0000000..54ec0b6 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_oauth_issuer_off.json @@ -0,0 +1,11 @@ +{ + "status": 401, + "body": { + "detail": "Unauthorized" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_oauth_only.json b/tests/fixtures/parity/legacy/errors__auth_oauth_only.json new file mode 100644 index 0000000..4fdb761 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__auth_oauth_only.json @@ -0,0 +1,12 @@ +{ + "status": 403, + "body": { + "detail": "An API key's webhook secret is managed on the API credentials page (https://lenz.io/api-credentials). This endpoint is for OAuth connections.", + "code": "oauth_only" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_history.json b/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_history.json index e691e72..627261e 100644 --- a/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_history.json +++ b/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_history.json @@ -1,13 +1,13 @@ { "status": 403, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This report is private.", "code": "private_claim", "error": "private_claim" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_send.json b/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_send.json index e691e72..627261e 100644 --- a/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_send.json +++ b/tests/fixtures/parity/legacy/errors__auth_private_claim_ask_send.json @@ -1,13 +1,13 @@ { "status": 403, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This report is private.", "code": "private_claim", "error": "private_claim" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__auth_unrecognised_prefix.json b/tests/fixtures/parity/legacy/errors__auth_unrecognised_prefix.json index 8dd2fb4..54ec0b6 100644 --- a/tests/fixtures/parity/legacy/errors__auth_unrecognised_prefix.json +++ b/tests/fixtures/parity/legacy/errors__auth_unrecognised_prefix.json @@ -1,11 +1,11 @@ { "status": 401, + "body": { + "detail": "Unauthorized" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized" } } diff --git a/tests/fixtures/parity/legacy/errors__http_error_library_bad_curated.json b/tests/fixtures/parity/legacy/errors__http_error_library_bad_curated.json index 03f1508..0a644ad 100644 --- a/tests/fixtures/parity/legacy/errors__http_error_library_bad_curated.json +++ b/tests/fixtures/parity/legacy/errors__http_error_library_bad_curated.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Invalid curated list(s). Allowed: trivia" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Invalid curated list(s). Allowed: trivia" } } diff --git a/tests/fixtures/parity/legacy/errors__http_error_library_bad_verdict.json b/tests/fixtures/parity/legacy/errors__http_error_library_bad_verdict.json index 68f0346..0e8a48d 100644 --- a/tests/fixtures/parity/legacy/errors__http_error_library_bad_verdict.json +++ b/tests/fixtures/parity/legacy/errors__http_error_library_bad_verdict.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Invalid verdict label(s). Allowed: False, Mostly False, Mixed, Mostly True, True" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Invalid verdict label(s). Allowed: False, Mostly False, Mixed, Mostly True, True" } } diff --git a/tests/fixtures/parity/legacy/errors__method_not_allowed_get_verify.json b/tests/fixtures/parity/legacy/errors__method_not_allowed_get_verify.json new file mode 100644 index 0000000..a769f68 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__method_not_allowed_get_verify.json @@ -0,0 +1,11 @@ +{ + "status": 405, + "body": { + "": "Method not allowed" + }, + "headers": { + "Content-Type": "text/html; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__method_not_allowed_post_library.json b/tests/fixtures/parity/legacy/errors__method_not_allowed_post_library.json new file mode 100644 index 0000000..a769f68 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__method_not_allowed_post_library.json @@ -0,0 +1,11 @@ +{ + "status": 405, + "body": { + "": "Method not allowed" + }, + "headers": { + "Content-Type": "text/html; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__not_found_ask.json b/tests/fixtures/parity/legacy/errors__not_found_ask.json index c0d18e1..65ff442 100644 --- a/tests/fixtures/parity/legacy/errors__not_found_ask.json +++ b/tests/fixtures/parity/legacy/errors__not_found_ask.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "detail": "Verification not found." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Verification not found." } } diff --git a/tests/fixtures/parity/legacy/errors__not_found_route.json b/tests/fixtures/parity/legacy/errors__not_found_route.json index 06110be..a16648d 100644 --- a/tests/fixtures/parity/legacy/errors__not_found_route.json +++ b/tests/fixtures/parity/legacy/errors__not_found_route.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "": "" + }, "headers": { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "": "" } } diff --git a/tests/fixtures/parity/legacy/errors__not_found_verification.json b/tests/fixtures/parity/legacy/errors__not_found_verification.json index 3bf3204..538732c 100644 --- a/tests/fixtures/parity/legacy/errors__not_found_verification.json +++ b/tests/fixtures/parity/legacy/errors__not_found_verification.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "detail": "Not found." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Not found." } } diff --git a/tests/fixtures/parity/legacy/errors__not_found_verify_status.json b/tests/fixtures/parity/legacy/errors__not_found_verify_status.json index 09c1e79..d005db5 100644 --- a/tests/fixtures/parity/legacy/errors__not_found_verify_status.json +++ b/tests/fixtures/parity/legacy/errors__not_found_verify_status.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "detail": "Task not found." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Task not found." } } diff --git a/tests/fixtures/parity/legacy/errors__oauth_register_disabled.json b/tests/fixtures/parity/legacy/errors__oauth_register_disabled.json new file mode 100644 index 0000000..a16648d --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__oauth_register_disabled.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "body": { + "": "" + }, + "headers": { + "Content-Type": "text/html; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__oauth_register_invalid_client_metadata.json b/tests/fixtures/parity/legacy/errors__oauth_register_invalid_client_metadata.json new file mode 100644 index 0000000..461c91d --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__oauth_register_invalid_client_metadata.json @@ -0,0 +1,12 @@ +{ + "status": 400, + "body": { + "error": "invalid_client_metadata", + "error_description": "token_endpoint_auth_method must be none: Lenz registers public clients that use PKCE." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__oauth_register_invalid_redirect_uri.json b/tests/fixtures/parity/legacy/errors__oauth_register_invalid_redirect_uri.json new file mode 100644 index 0000000..63e62ba --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__oauth_register_invalid_redirect_uri.json @@ -0,0 +1,12 @@ +{ + "status": 400, + "body": { + "error": "invalid_redirect_uri", + "error_description": "Each redirect URI must be https, or http on localhost, 127.0.0.1 or [::1], without a fragment." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__oauth_revoke_invalid_client.json b/tests/fixtures/parity/legacy/errors__oauth_revoke_invalid_client.json new file mode 100644 index 0000000..a7a70ef --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__oauth_revoke_invalid_client.json @@ -0,0 +1,13 @@ +{ + "status": 401, + "body": { + "error": "invalid_client", + "error_description": "Client authentication failed." + }, + "headers": { + "Content-Type": "application/json", + "WWW-Authenticate": "Basic realm=\"lenz\"", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__oauth_token_invalid_client.json b/tests/fixtures/parity/legacy/errors__oauth_token_invalid_client.json new file mode 100644 index 0000000..a7a70ef --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__oauth_token_invalid_client.json @@ -0,0 +1,13 @@ +{ + "status": 401, + "body": { + "error": "invalid_client", + "error_description": "Client authentication failed." + }, + "headers": { + "Content-Type": "application/json", + "WWW-Authenticate": "Basic realm=\"lenz\"", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__oauth_token_invalid_grant.json b/tests/fixtures/parity/legacy/errors__oauth_token_invalid_grant.json new file mode 100644 index 0000000..88c6f64 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__oauth_token_invalid_grant.json @@ -0,0 +1,12 @@ +{ + "status": 400, + "body": { + "error": "invalid_grant", + "error_description": "The authorization is invalid or has expired." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__oauth_token_missing_grant_type.json b/tests/fixtures/parity/legacy/errors__oauth_token_missing_grant_type.json new file mode 100644 index 0000000..f989e00 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__oauth_token_missing_grant_type.json @@ -0,0 +1,11 @@ +{ + "status": 400, + "body": { + "error": "unsupported_grant_type" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__oauth_token_refresh_invalid_grant.json b/tests/fixtures/parity/legacy/errors__oauth_token_refresh_invalid_grant.json new file mode 100644 index 0000000..88c6f64 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__oauth_token_refresh_invalid_grant.json @@ -0,0 +1,12 @@ +{ + "status": 400, + "body": { + "error": "invalid_grant", + "error_description": "The authorization is invalid or has expired." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__oauth_token_unsupported_grant_type.json b/tests/fixtures/parity/legacy/errors__oauth_token_unsupported_grant_type.json new file mode 100644 index 0000000..f989e00 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__oauth_token_unsupported_grant_type.json @@ -0,0 +1,11 @@ +{ + "status": 400, + "body": { + "error": "unsupported_grant_type" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/errors__payment_required_ask.json b/tests/fixtures/parity/legacy/errors__payment_required_ask.json index 6648329..cd203cc 100644 --- a/tests/fixtures/parity/legacy/errors__payment_required_ask.json +++ b/tests/fixtures/parity/legacy/errors__payment_required_ask.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining ask credits.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__payment_required_assess.json b/tests/fixtures/parity/legacy/errors__payment_required_assess.json index 1cd3038..50f67b4 100644 --- a/tests/fixtures/parity/legacy/errors__payment_required_assess.json +++ b/tests/fixtures/parity/legacy/errors__payment_required_assess.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining /assess units.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__payment_required_verify.json b/tests/fixtures/parity/legacy/errors__payment_required_verify.json index 32f50ac..bf3a6b1 100644 --- a/tests/fixtures/parity/legacy/errors__payment_required_verify.json +++ b/tests/fixtures/parity/legacy/errors__payment_required_verify.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining claim checks.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 10 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__payment_required_verify_batch_short.json b/tests/fixtures/parity/legacy/errors__payment_required_verify_batch_short.json index 1caec0e..70c05cb 100644 --- a/tests/fixtures/parity/legacy/errors__payment_required_verify_batch_short.json +++ b/tests/fixtures/parity/legacy/errors__payment_required_verify_batch_short.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Insufficient credits for batch.", "code": "no_credits", @@ -13,8 +8,13 @@ "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "requested": 5, "remaining": 3, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 30, "cost": 50 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__rate_limited_extract.json b/tests/fixtures/parity/legacy/errors__rate_limited_extract.json index 9e6149c..1865066 100644 --- a/tests/fixtures/parity/legacy/errors__rate_limited_extract.json +++ b/tests/fixtures/parity/legacy/errors__rate_limited_extract.json @@ -1,11 +1,5 @@ { "status": 429, - "headers": { - "Content-Type": "application/json", - "Retry-After": "900", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", "code": "extract_daily_limit", @@ -13,5 +7,11 @@ "reset_in_seconds": 900, "doc_url": "https://lenz.io/docs/errors#rate-limits", "upgrade_url": "https://lenz.io/plans" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "900", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__service_unavailable_ask.json b/tests/fixtures/parity/legacy/errors__service_unavailable_ask.json index dac95ca..88544c1 100644 --- a/tests/fixtures/parity/legacy/errors__service_unavailable_ask.json +++ b/tests/fixtures/parity/legacy/errors__service_unavailable_ask.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "The chat model is unavailable right now. Retry shortly.", "code": "upstream_unavailable", "retry_after": 90, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__service_unavailable_capacity.json b/tests/fixtures/parity/legacy/errors__service_unavailable_capacity.json index 124f80e..b26cfff 100644 --- a/tests/fixtures/parity/legacy/errors__service_unavailable_capacity.json +++ b/tests/fixtures/parity/legacy/errors__service_unavailable_capacity.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "60", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": 60, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__validation_malformed_json.json b/tests/fixtures/parity/legacy/errors__validation_malformed_json.json index 0c5de40..4d130b1 100644 --- a/tests/fixtures/parity/legacy/errors__validation_malformed_json.json +++ b/tests/fixtures/parity/legacy/errors__validation_malformed_json.json @@ -1,11 +1,11 @@ { "status": 400, + "body": { + "detail": "Cannot parse request body (Expecting property name enclosed in double quotes: line 1 column 2 (char 1))" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Cannot parse request body (Expecting property name enclosed in double quotes: line 1 column 2 (char 1))" } } diff --git a/tests/fixtures/parity/legacy/errors__validation_missing_field_hint.json b/tests/fixtures/parity/legacy/errors__validation_missing_field_hint.json index 86c632f..b887034 100644 --- a/tests/fixtures/parity/legacy/errors__validation_missing_field_hint.json +++ b/tests/fixtures/parity/legacy/errors__validation_missing_field_hint.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -23,5 +18,10 @@ "content", "bogus" ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__validation_unknown_field_only.json b/tests/fixtures/parity/legacy/errors__validation_unknown_field_only.json index 98527f4..c83cdc2 100644 --- a/tests/fixtures/parity/legacy/errors__validation_unknown_field_only.json +++ b/tests/fixtures/parity/legacy/errors__validation_unknown_field_only.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -22,5 +17,10 @@ "unrecognized_fields": [ "statement" ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__validation_unknown_field_wrong_type.json b/tests/fixtures/parity/legacy/errors__validation_unknown_field_wrong_type.json index 643f307..3aec659 100644 --- a/tests/fixtures/parity/legacy/errors__validation_unknown_field_wrong_type.json +++ b/tests/fixtures/parity/legacy/errors__validation_unknown_field_wrong_type.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -21,5 +16,10 @@ "bogus_field", "another" ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__validation_wrong_type.json b/tests/fixtures/parity/legacy/errors__validation_wrong_type.json index 0c8074f..a2c9bcb 100644 --- a/tests/fixtures/parity/legacy/errors__validation_wrong_type.json +++ b/tests/fixtures/parity/legacy/errors__validation_wrong_type.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -17,5 +12,10 @@ "msg": "Input should be a valid string" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/errors__web_assess_payment_required.json b/tests/fixtures/parity/legacy/errors__web_assess_payment_required.json new file mode 100644 index 0000000..5e8991b --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__web_assess_payment_required.json @@ -0,0 +1,19 @@ +{ + "status": 402, + "body": { + "detail": "No assessments left this month.", + "code": "no_credits", + "doc_url": "https://lenz.io/docs/errors#quota", + "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", + "remaining": 0, + "resets_at": "2026-10-01T14:07:00+00:00", + "credits_remaining": 0, + "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "Cookie" + } +} diff --git a/tests/fixtures/parity/legacy/errors__web_assess_signup_required.json b/tests/fixtures/parity/legacy/errors__web_assess_signup_required.json new file mode 100644 index 0000000..7621cf2 --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__web_assess_signup_required.json @@ -0,0 +1,14 @@ +{ + "status": 403, + "body": { + "detail": "Sign up to check this — it’s free.", + "code": "signup_required", + "signup_claim_stashed": false, + "attempt": "e2fffcdbaf5c6cfc1939f3eaec689a87" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "Cookie" + } +} diff --git a/tests/fixtures/parity/legacy/errors__web_review_rate_limited.json b/tests/fixtures/parity/legacy/errors__web_review_rate_limited.json new file mode 100644 index 0000000..0e7609f --- /dev/null +++ b/tests/fixtures/parity/legacy/errors__web_review_rate_limited.json @@ -0,0 +1,17 @@ +{ + "status": 429, + "body": { + "detail": "This account has used its extractions for today. The daily allowance is shared with the Lenz API. It resets at 00:00 UTC.", + "code": "extract_daily_limit", + "limit": 1000, + "reset_in_seconds": 777, + "doc_url": "https://lenz.io/docs/errors#rate-limits", + "upgrade_url": "https://lenz.io/plans" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "777", + "Cache-Control": "no-store", + "Vary": "Cookie" + } +} diff --git a/tests/fixtures/parity/legacy/extract__401_no_key.json b/tests/fixtures/parity/legacy/extract__401_no_key.json index 8dd2fb4..54ec0b6 100644 --- a/tests/fixtures/parity/legacy/extract__401_no_key.json +++ b/tests/fixtures/parity/legacy/extract__401_no_key.json @@ -1,11 +1,11 @@ { "status": 401, + "body": { + "detail": "Unauthorized" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized" } } diff --git a/tests/fixtures/parity/legacy/extract__422_blank_text.json b/tests/fixtures/parity/legacy/extract__422_blank_text.json index 1ebb88e..367f620 100644 --- a/tests/fixtures/parity/legacy/extract__422_blank_text.json +++ b/tests/fixtures/parity/legacy/extract__422_blank_text.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Text is required." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Text is required." } } diff --git a/tests/fixtures/parity/legacy/extract__422_focus_too_long.json b/tests/fixtures/parity/legacy/extract__422_focus_too_long.json index 5804588..2f948a8 100644 --- a/tests/fixtures/parity/legacy/extract__422_focus_too_long.json +++ b/tests/fixtures/parity/legacy/extract__422_focus_too_long.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "focus must be at most 300 characters of plain text." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "focus must be at most 300 characters of plain text." } } diff --git a/tests/fixtures/parity/legacy/extract__422_missing_text.json b/tests/fixtures/parity/legacy/extract__422_missing_text.json index 9e6d6c0..d0c7bfd 100644 --- a/tests/fixtures/parity/legacy/extract__422_missing_text.json +++ b/tests/fixtures/parity/legacy/extract__422_missing_text.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -17,5 +12,10 @@ "msg": "Field required" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__429_daily_limit.json b/tests/fixtures/parity/legacy/extract__429_daily_limit.json index 729effe..1181cbb 100644 --- a/tests/fixtures/parity/legacy/extract__429_daily_limit.json +++ b/tests/fixtures/parity/legacy/extract__429_daily_limit.json @@ -1,11 +1,5 @@ { "status": 429, - "headers": { - "Content-Type": "application/json", - "Retry-After": "3600", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Daily /extract limit of 1000 reached for this account. The allowance is shared by every key on the account and by extractions run from the Lenz website.", "code": "extract_daily_limit", @@ -13,5 +7,11 @@ "reset_in_seconds": 3600, "doc_url": "https://lenz.io/docs/errors#rate-limits", "upgrade_url": "https://lenz.io/plans" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "3600", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__502_extraction_failed.json b/tests/fixtures/parity/legacy/extract__502_extraction_failed.json index 7deef02..529fe27 100644 --- a/tests/fixtures/parity/legacy/extract__502_extraction_failed.json +++ b/tests/fixtures/parity/legacy/extract__502_extraction_failed.json @@ -1,13 +1,13 @@ { "status": 502, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Extraction failed", "code": "extraction_failed", "error": "extraction_failed" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__503_upstream_unavailable.json b/tests/fixtures/parity/legacy/extract__503_upstream_unavailable.json index b308e0c..9308b85 100644 --- a/tests/fixtures/parity/legacy/extract__503_upstream_unavailable.json +++ b/tests/fixtures/parity/legacy/extract__503_upstream_unavailable.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Our model providers are temporarily unavailable. Please retry shortly.", "code": "upstream_unavailable", "retry_after": 90, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__focus_ready.json b/tests/fixtures/parity/legacy/extract__focus_ready.json index 196fca1..2ded502 100644 --- a/tests/fixtures/parity/legacy/extract__focus_ready.json +++ b/tests/fixtures/parity/legacy/extract__focus_ready.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Beta fell 3% last year.", @@ -24,5 +19,10 @@ "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", "locations": null + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__idempotency_body_mismatch_422.json b/tests/fixtures/parity/legacy/extract__idempotency_body_mismatch_422.json index ef04562..2425649 100644 --- a/tests/fixtures/parity/legacy/extract__idempotency_body_mismatch_422.json +++ b/tests/fixtures/parity/legacy/extract__idempotency_body_mismatch_422.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Idempotency-Key reused with a different request body." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Idempotency-Key reused with a different request body." } } diff --git a/tests/fixtures/parity/legacy/extract__idempotency_replay.json b/tests/fixtures/parity/legacy/extract__idempotency_replay.json index 8fff1c2..8f23ae8 100644 --- a/tests/fixtures/parity/legacy/extract__idempotency_replay.json +++ b/tests/fixtures/parity/legacy/extract__idempotency_replay.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Alpha rose 5% in 2024.", @@ -27,5 +22,10 @@ "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", "locations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__locate_all_dropped.json b/tests/fixtures/parity/legacy/extract__locate_all_dropped.json index 53117ce..b1365bf 100644 --- a/tests/fixtures/parity/legacy/extract__locate_all_dropped.json +++ b/tests/fixtures/parity/legacy/extract__locate_all_dropped.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "not_a_claim", "claim": "", @@ -24,5 +19,10 @@ "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", "locations": [] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__locate_failed.json b/tests/fixtures/parity/legacy/extract__locate_failed.json index 25c0403..e31d700 100644 --- a/tests/fixtures/parity/legacy/extract__locate_failed.json +++ b/tests/fixtures/parity/legacy/extract__locate_failed.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Alpha rose 5% in 2024.", @@ -27,5 +22,10 @@ "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", "locations": null + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__locate_leading_whitespace.json b/tests/fixtures/parity/legacy/extract__locate_leading_whitespace.json index 7479a3e..b59ad27 100644 --- a/tests/fixtures/parity/legacy/extract__locate_leading_whitespace.json +++ b/tests/fixtures/parity/legacy/extract__locate_leading_whitespace.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Alpha rose 5% in 2024.", @@ -35,5 +30,10 @@ ] } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__locate_some_dropped.json b/tests/fixtures/parity/legacy/extract__locate_some_dropped.json index 6e51827..c059de8 100644 --- a/tests/fixtures/parity/legacy/extract__locate_some_dropped.json +++ b/tests/fixtures/parity/legacy/extract__locate_some_dropped.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Alpha rose 5% in 2024.", @@ -48,5 +43,10 @@ ] } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__locate_true.json b/tests/fixtures/parity/legacy/extract__locate_true.json index 6e51827..c059de8 100644 --- a/tests/fixtures/parity/legacy/extract__locate_true.json +++ b/tests/fixtures/parity/legacy/extract__locate_true.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Alpha rose 5% in 2024.", @@ -48,5 +43,10 @@ ] } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__no_match_with_focus.json b/tests/fixtures/parity/legacy/extract__no_match_with_focus.json index 0b34d79..45eb087 100644 --- a/tests/fixtures/parity/legacy/extract__no_match_with_focus.json +++ b/tests/fixtures/parity/legacy/extract__no_match_with_focus.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "no_match", "claim": "", @@ -15,5 +10,10 @@ "presumed_intent": "", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", "locations": null + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__not_a_claim.json b/tests/fixtures/parity/legacy/extract__not_a_claim.json index 265efee..a9af794 100644 --- a/tests/fixtures/parity/legacy/extract__not_a_claim.json +++ b/tests/fixtures/parity/legacy/extract__not_a_claim.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "not_a_claim", "claim": "", @@ -15,5 +10,10 @@ "presumed_intent": "", "original_input": "What a lovely day.", "locations": null + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__not_a_claim_beside_claims.json b/tests/fixtures/parity/legacy/extract__not_a_claim_beside_claims.json index 97f66d5..4e6718b 100644 --- a/tests/fixtures/parity/legacy/extract__not_a_claim_beside_claims.json +++ b/tests/fixtures/parity/legacy/extract__not_a_claim_beside_claims.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "not_a_claim", "claim": "Alpha rose 5% in 2024.", @@ -24,5 +19,10 @@ "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024.", "locations": null + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__ready_one_claim.json b/tests/fixtures/parity/legacy/extract__ready_one_claim.json index 0a32c8b..1b9b2b6 100644 --- a/tests/fixtures/parity/legacy/extract__ready_one_claim.json +++ b/tests/fixtures/parity/legacy/extract__ready_one_claim.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Alpha rose 5% in 2024.", @@ -24,5 +19,10 @@ "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024.", "locations": null + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__ready_several_claims.json b/tests/fixtures/parity/legacy/extract__ready_several_claims.json index 25c0403..e31d700 100644 --- a/tests/fixtures/parity/legacy/extract__ready_several_claims.json +++ b/tests/fixtures/parity/legacy/extract__ready_several_claims.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Alpha rose 5% in 2024.", @@ -27,5 +22,10 @@ "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", "locations": null + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__replay_later_200.json b/tests/fixtures/parity/legacy/extract__replay_later_200.json index 8fff1c2..8f23ae8 100644 --- a/tests/fixtures/parity/legacy/extract__replay_later_200.json +++ b/tests/fixtures/parity/legacy/extract__replay_later_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Alpha rose 5% in 2024.", @@ -27,5 +22,10 @@ "presumed_intent": "Verify reported figures", "original_input": "Alpha rose 5% in 2024. Beta fell 3% last year.", "locations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__url_fetch_502_unreadable.json b/tests/fixtures/parity/legacy/extract__url_fetch_502_unreadable.json index 7deef02..529fe27 100644 --- a/tests/fixtures/parity/legacy/extract__url_fetch_502_unreadable.json +++ b/tests/fixtures/parity/legacy/extract__url_fetch_502_unreadable.json @@ -1,13 +1,13 @@ { "status": 502, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Extraction failed", "code": "extraction_failed", "error": "extraction_failed" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__url_fetch_503_upstream.json b/tests/fixtures/parity/legacy/extract__url_fetch_503_upstream.json index 7cbd9f8..3b1746c 100644 --- a/tests/fixtures/parity/legacy/extract__url_fetch_503_upstream.json +++ b/tests/fixtures/parity/legacy/extract__url_fetch_503_upstream.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "The page could not be read right now. Please retry shortly.", "code": "upstream_unavailable", "retry_after": 90, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/extract__url_input_located.json b/tests/fixtures/parity/legacy/extract__url_input_located.json index 2cacb24..8505b1e 100644 --- a/tests/fixtures/parity/legacy/extract__url_input_located.json +++ b/tests/fixtures/parity/legacy/extract__url_input_located.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "ready", "claim": "Alpha rose 5% in 2024.", @@ -35,5 +30,10 @@ ] } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__401_no_credentials.json b/tests/fixtures/parity/legacy/review__401_no_credentials.json index 8dd2fb4..54ec0b6 100644 --- a/tests/fixtures/parity/legacy/review__401_no_credentials.json +++ b/tests/fixtures/parity/legacy/review__401_no_credentials.json @@ -1,11 +1,11 @@ { "status": 401, + "body": { + "detail": "Unauthorized" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized" } } diff --git a/tests/fixtures/parity/legacy/review__402_no_credits.json b/tests/fixtures/parity/legacy/review__402_no_credits.json index c9adf9a..8fd4d67 100644 --- a/tests/fixtures/parity/legacy/review__402_no_credits.json +++ b/tests/fixtures/parity/legacy/review__402_no_credits.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining credits to assess the draft.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 100, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 100, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__402_no_credits_exhausted.json b/tests/fixtures/parity/legacy/review__402_no_credits_exhausted.json index cbcd2d1..591f328 100644 --- a/tests/fixtures/parity/legacy/review__402_no_credits_exhausted.json +++ b/tests/fixtures/parity/legacy/review__402_no_credits_exhausted.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining credits to assess the draft.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 1 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_blank_text.json b/tests/fixtures/parity/legacy/review__422_blank_text.json index b820499..b62d04a 100644 --- a/tests/fixtures/parity/legacy/review__422_blank_text.json +++ b/tests/fixtures/parity/legacy/review__422_blank_text.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "text: send the draft, or one public http(s) URL.", "code": "validation_error", @@ -17,5 +12,10 @@ "msg": "text: send the draft, or one public http(s) URL." } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_citations_options_object.json b/tests/fixtures/parity/legacy/review__422_citations_options_object.json index 1f3923f..a09435f 100644 --- a/tests/fixtures/parity/legacy/review__422_citations_options_object.json +++ b/tests/fixtures/parity/legacy/review__422_citations_options_object.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.citations: Extra inputs are not permitted", "code": "validation_error", @@ -18,5 +13,10 @@ "msg": "Extra inputs are not permitted" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_depth_unknown.json b/tests/fixtures/parity/legacy/review__422_depth_unknown.json index dcce2ae..e2c2889 100644 --- a/tests/fixtures/parity/legacy/review__422_depth_unknown.json +++ b/tests/fixtures/parity/legacy/review__422_depth_unknown.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.escalate.depth: Input should be 'standard' or 'low'", "code": "validation_error", @@ -19,5 +14,10 @@ "msg": "Input should be 'standard' or 'low'" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_invalid_confidence_band.json b/tests/fixtures/parity/legacy/review__422_invalid_confidence_band.json index 8dccb97..32e16e2 100644 --- a/tests/fixtures/parity/legacy/review__422_invalid_confidence_band.json +++ b/tests/fixtures/parity/legacy/review__422_invalid_confidence_band.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.escalate.confidence: Unknown confidence band 'certain'; use low, medium or high.", "code": "invalid_confidence_band", @@ -19,5 +14,10 @@ "msg": "Unknown confidence band 'certain'; use low, medium or high." } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_invalid_verdict_label.json b/tests/fixtures/parity/legacy/review__422_invalid_verdict_label.json index 40f409f..320e56a 100644 --- a/tests/fixtures/parity/legacy/review__422_invalid_verdict_label.json +++ b/tests/fixtures/parity/legacy/review__422_invalid_verdict_label.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.escalate.verdicts: Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True.", "code": "invalid_verdict_label", @@ -19,5 +14,10 @@ "msg": "Unknown verdict label 'Misleading'; use one of: False, Mostly False, Mixed, Mostly True, True." } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_max_assessments_negative.json b/tests/fixtures/parity/legacy/review__422_max_assessments_negative.json index c88a65e..0715227 100644 --- a/tests/fixtures/parity/legacy/review__422_max_assessments_negative.json +++ b/tests/fixtures/parity/legacy/review__422_max_assessments_negative.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.escalate.max_assessments: Input should be greater than or equal to 0", "code": "validation_error", @@ -19,5 +14,10 @@ "msg": "Input should be greater than or equal to 0" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_max_citations_negative.json b/tests/fixtures/parity/legacy/review__422_max_citations_negative.json index 13e166c..46dc9ee 100644 --- a/tests/fixtures/parity/legacy/review__422_max_citations_negative.json +++ b/tests/fixtures/parity/legacy/review__422_max_citations_negative.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.escalate.max_citations: Input should be greater than or equal to 0", "code": "validation_error", @@ -19,5 +14,10 @@ "msg": "Input should be greater than or equal to 0" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_max_citations_too_big.json b/tests/fixtures/parity/legacy/review__422_max_citations_too_big.json index 10fcf2c..7ec1805 100644 --- a/tests/fixtures/parity/legacy/review__422_max_citations_too_big.json +++ b/tests/fixtures/parity/legacy/review__422_max_citations_too_big.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.escalate.max_citations: Input should be less than or equal to 20", "code": "validation_error", @@ -19,5 +14,10 @@ "msg": "Input should be less than or equal to 20" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_max_verifications_too_big.json b/tests/fixtures/parity/legacy/review__422_max_verifications_too_big.json index 9c2e2eb..c5c773b 100644 --- a/tests/fixtures/parity/legacy/review__422_max_verifications_too_big.json +++ b/tests/fixtures/parity/legacy/review__422_max_verifications_too_big.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.escalate.max_verifications: Input should be less than or equal to 20", "code": "validation_error", @@ -19,5 +14,10 @@ "msg": "Input should be less than or equal to 20" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_text_missing.json b/tests/fixtures/parity/legacy/review__422_text_missing.json index de972a9..8380243 100644 --- a/tests/fixtures/parity/legacy/review__422_text_missing.json +++ b/tests/fixtures/parity/legacy/review__422_text_missing.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.text: Field required", "code": "validation_error", @@ -18,5 +13,10 @@ "msg": "Field required" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_text_wrong_type.json b/tests/fixtures/parity/legacy/review__422_text_wrong_type.json index 2638c63..696b78e 100644 --- a/tests/fixtures/parity/legacy/review__422_text_wrong_type.json +++ b/tests/fixtures/parity/legacy/review__422_text_wrong_type.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.text: Input should be a valid string", "code": "validation_error", @@ -18,5 +13,10 @@ "msg": "Input should be a valid string" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_unknown_escalate_field.json b/tests/fixtures/parity/legacy/review__422_unknown_escalate_field.json index 2c5c7e9..d188f40 100644 --- a/tests/fixtures/parity/legacy/review__422_unknown_escalate_field.json +++ b/tests/fixtures/parity/legacy/review__422_unknown_escalate_field.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.escalate.nope: Extra inputs are not permitted", "code": "validation_error", @@ -19,5 +14,10 @@ "msg": "Extra inputs are not permitted" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_unknown_top_level_field.json b/tests/fixtures/parity/legacy/review__422_unknown_top_level_field.json index f91e1f3..ea96224 100644 --- a/tests/fixtures/parity/legacy/review__422_unknown_top_level_field.json +++ b/tests/fixtures/parity/legacy/review__422_unknown_top_level_field.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.max_verifications: Extra inputs are not permitted", "code": "validation_error", @@ -18,5 +13,10 @@ "msg": "Extra inputs are not permitted" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_unsupported_language.json b/tests/fixtures/parity/legacy/review__422_unsupported_language.json index 26f0a19..ef3d68b 100644 --- a/tests/fixtures/parity/legacy/review__422_unsupported_language.json +++ b/tests/fixtures/parity/legacy/review__422_unsupported_language.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "language: Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact.", "code": "validation_error", @@ -17,5 +12,10 @@ "msg": "language: Unsupported language 'xx'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact." } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_visibility_public.json b/tests/fixtures/parity/legacy/review__422_visibility_public.json index 3c72623..3b923ea 100644 --- a/tests/fixtures/parity/legacy/review__422_visibility_public.json +++ b/tests/fixtures/parity/legacy/review__422_visibility_public.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "payload.visibility: Input should be 'private' or 'unlisted'", "code": "validation_error", @@ -18,5 +13,10 @@ "msg": "Input should be 'private' or 'unlisted'" } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__422_webhook_secret_missing.json b/tests/fixtures/parity/legacy/review__422_webhook_secret_missing.json new file mode 100644 index 0000000..1ecf2d1 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__422_webhook_secret_missing.json @@ -0,0 +1,21 @@ +{ + "status": 422, + "body": { + "detail": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend.", + "code": "webhook_secret_missing", + "errors": [ + { + "loc": [ + "body", + "webhook_url" + ], + "msg": "webhook_url was supplied but this credential has no webhook signing secret. Create one on the API credentials page (an API key) or read GET /me/webhook-secret (an OAuth connection), then resend." + } + ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/review__429_extract_daily_limit.json b/tests/fixtures/parity/legacy/review__429_extract_daily_limit.json index f7f182a..1bc25ba 100644 --- a/tests/fixtures/parity/legacy/review__429_extract_daily_limit.json +++ b/tests/fixtures/parity/legacy/review__429_extract_daily_limit.json @@ -1,11 +1,5 @@ { "status": 429, - "headers": { - "Content-Type": "application/json", - "Retry-After": "60", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Daily /extract limit of 1000 reached for this account. A review of a URL reads the page like /extract and counts as one /extract call.", "code": "extract_daily_limit", @@ -13,5 +7,11 @@ "reset_in_seconds": 60, "doc_url": "https://lenz.io/docs/errors#rate-limits", "upgrade_url": "https://lenz.io/plans" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "60", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__429_review_in_flight.json b/tests/fixtures/parity/legacy/review__429_review_in_flight.json index c8777a5..2129d2a 100644 --- a/tests/fixtures/parity/legacy/review__429_review_in_flight.json +++ b/tests/fixtures/parity/legacy/review__429_review_in_flight.json @@ -1,14 +1,14 @@ { "status": 429, + "body": { + "detail": "This account already has 3 reviews running. Retry when one completes.", + "code": "review_in_flight", + "retry_after_seconds": 60 + }, "headers": { "Content-Type": "application/json", "Retry-After": "60", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "This account already has 3 reviews running. Retry when one completes.", - "code": "review_in_flight", - "retry_after_seconds": 60 } } diff --git a/tests/fixtures/parity/legacy/review__503_capacity.json b/tests/fixtures/parity/legacy/review__503_capacity.json index adcc209..085990c 100644 --- a/tests/fixtures/parity/legacy/review__503_capacity.json +++ b/tests/fixtures/parity/legacy/review__503_capacity.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": 90, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__503_citations_capacity.json b/tests/fixtures/parity/legacy/review__503_citations_capacity.json index adcc209..085990c 100644 --- a/tests/fixtures/parity/legacy/review__503_citations_capacity.json +++ b/tests/fixtures/parity/legacy/review__503_citations_capacity.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "90", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": 90, "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "90", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__delete_not_a_route.json b/tests/fixtures/parity/legacy/review__delete_not_a_route.json new file mode 100644 index 0000000..a769f68 --- /dev/null +++ b/tests/fixtures/parity/legacy/review__delete_not_a_route.json @@ -0,0 +1,11 @@ +{ + "status": 405, + "body": { + "": "Method not allowed" + }, + "headers": { + "Content-Type": "text/html; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/review__get_403_insufficient_scope.json b/tests/fixtures/parity/legacy/review__get_403_insufficient_scope.json index 80c529c..b6b8f4f 100644 --- a/tests/fixtures/parity/legacy/review__get_403_insufficient_scope.json +++ b/tests/fixtures/parity/legacy/review__get_403_insufficient_scope.json @@ -1,14 +1,14 @@ { "status": 403, + "body": { + "detail": "The access token does not allow this call.", + "code": "insufficient_scope", + "scope": "history:read" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "WWW-Authenticate": "Bearer error=\"insufficient_scope\", scope=\"history:read\", resource_metadata=\"https://lenz.io/.well-known/oauth-protected-resource/api/v1\"", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "The access token does not allow this call.", - "code": "insufficient_scope", - "scope": "history:read" } } diff --git a/tests/fixtures/parity/legacy/review__get_404_not_found.json b/tests/fixtures/parity/legacy/review__get_404_not_found.json index 8045cd8..e73d347 100644 --- a/tests/fixtures/parity/legacy/review__get_404_not_found.json +++ b/tests/fixtures/parity/legacy/review__get_404_not_found.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Review not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Review not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/legacy/review__get_404_other_account.json b/tests/fixtures/parity/legacy/review__get_404_other_account.json index 8045cd8..e73d347 100644 --- a/tests/fixtures/parity/legacy/review__get_404_other_account.json +++ b/tests/fixtures/parity/legacy/review__get_404_other_account.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Review not found.", + "code": "not_found" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Review not found.", - "code": "not_found" } } diff --git a/tests/fixtures/parity/legacy/review__get_410_purged.json b/tests/fixtures/parity/legacy/review__get_410_purged.json index bedf6a5..396b15a 100644 --- a/tests/fixtures/parity/legacy/review__get_410_purged.json +++ b/tests/fixtures/parity/legacy/review__get_410_purged.json @@ -1,13 +1,13 @@ { "status": 410, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This review is no longer available: its account removes content after a set period.", "code": "purged", "purged_at": "2026-10-01T09:07:00.123456Z" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_422_unknown_view.json b/tests/fixtures/parity/legacy/review__get_422_unknown_view.json index 531cbd7..c73271c 100644 --- a/tests/fixtures/parity/legacy/review__get_422_unknown_view.json +++ b/tests/fixtures/parity/legacy/review__get_422_unknown_view.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "view: use full or issues.", "code": "validation_error", @@ -17,5 +12,10 @@ "msg": "view: use full or issues." } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_assessing.json b/tests/fixtures/parity/legacy/review__get_assessing.json index eff0c0d..15f9bb2 100644 --- a/tests/fixtures/parity/legacy/review__get_assessing.json +++ b/tests/fixtures/parity/legacy/review__get_assessing.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "assessing", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -106,5 +101,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_assessment_rows_full_fields.json b/tests/fixtures/parity/legacy/review__get_assessment_rows_full_fields.json index c7b40ba..a63744a 100644 --- a/tests/fixtures/parity/legacy/review__get_assessment_rows_full_fields.json +++ b/tests/fixtures/parity/legacy/review__get_assessment_rows_full_fields.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -166,5 +161,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_clean.json b/tests/fixtures/parity/legacy/review__get_citations_clean.json index c4bb6cc..8b713d8 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_clean.json +++ b/tests/fixtures/parity/legacy/review__get_citations_clean.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -179,5 +174,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_failed_and_unchecked.json b/tests/fixtures/parity/legacy/review__get_citations_failed_and_unchecked.json index 39737a0..3d74122 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_failed_and_unchecked.json +++ b/tests/fixtures/parity/legacy/review__get_citations_failed_and_unchecked.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -195,5 +190,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_issue_full.json b/tests/fixtures/parity/legacy/review__get_citations_issue_full.json index df60b05..90333a3 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_issue_full.json +++ b/tests/fixtures/parity/legacy/review__get_citations_issue_full.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -201,5 +196,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_issue_issues_view.json b/tests/fixtures/parity/legacy/review__get_citations_issue_issues_view.json index c8414d9..676571c 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_issue_issues_view.json +++ b/tests/fixtures/parity/legacy/review__get_citations_issue_issues_view.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "issues", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -89,5 +84,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_limit_exactly_at_limit.json b/tests/fixtures/parity/legacy/review__get_citations_limit_exactly_at_limit.json index 9d9e9d7..117f684 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_limit_exactly_at_limit.json +++ b/tests/fixtures/parity/legacy/review__get_citations_limit_exactly_at_limit.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -179,5 +174,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_limit_reached.json b/tests/fixtures/parity/legacy/review__get_citations_limit_reached.json index 570c334..e4dd5cd 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_limit_reached.json +++ b/tests/fixtures/parity/legacy/review__get_citations_limit_reached.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -153,5 +148,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_no_claim_but_citations.json b/tests/fixtures/parity/legacy/review__get_citations_no_claim_but_citations.json index 5c19752..3025e57 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_no_claim_but_citations.json +++ b/tests/fixtures/parity/legacy/review__get_citations_no_claim_but_citations.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -148,5 +143,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_no_claim_no_citation.json b/tests/fixtures/parity/legacy/review__get_citations_no_claim_no_citation.json index c588505..eca6db3 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_no_claim_no_citation.json +++ b/tests/fixtures/parity/legacy/review__get_citations_no_claim_no_citation.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -64,5 +59,10 @@ "more_claims": null, "more_claim_locations": null, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_not_asked.json b/tests/fixtures/parity/legacy/review__get_citations_not_asked.json index 386fe10..f6afdaa 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_not_asked.json +++ b/tests/fixtures/parity/legacy/review__get_citations_not_asked.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -96,5 +91,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_only.json b/tests/fixtures/parity/legacy/review__get_citations_only.json index 287e33e..c5863b1 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_only.json +++ b/tests/fixtures/parity/legacy/review__get_citations_only.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -155,5 +150,10 @@ } ], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_partly_supported.json b/tests/fixtures/parity/legacy/review__get_citations_partly_supported.json index 6c96719..51ae0f4 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_partly_supported.json +++ b/tests/fixtures/parity/legacy/review__get_citations_partly_supported.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -179,5 +174,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_running.json b/tests/fixtures/parity/legacy/review__get_citations_running.json index e72b98c..b7ea324 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_running.json +++ b/tests/fixtures/parity/legacy/review__get_citations_running.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "verifying", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -163,5 +158,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_skipped_switched_off.json b/tests/fixtures/parity/legacy/review__get_citations_skipped_switched_off.json index b67e879..23514b6 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_skipped_switched_off.json +++ b/tests/fixtures/parity/legacy/review__get_citations_skipped_switched_off.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -96,5 +91,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_citations_skipped_url_input.json b/tests/fixtures/parity/legacy/review__get_citations_skipped_url_input.json index 04d13c0..976d0d6 100644 --- a/tests/fixtures/parity/legacy/review__get_citations_skipped_url_input.json +++ b/tests/fixtures/parity/legacy/review__get_citations_skipped_url_input.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -64,5 +59,10 @@ "more_claims": null, "more_claim_locations": null, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_claim_limit_not_reached.json b/tests/fixtures/parity/legacy/review__get_claim_limit_not_reached.json index 97b6112..3e0cb66 100644 --- a/tests/fixtures/parity/legacy/review__get_claim_limit_not_reached.json +++ b/tests/fixtures/parity/legacy/review__get_claim_limit_not_reached.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -126,5 +121,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_claim_limit_reached_exact.json b/tests/fixtures/parity/legacy/review__get_claim_limit_reached_exact.json index 55d5182..d044437 100644 --- a/tests/fixtures/parity/legacy/review__get_claim_limit_reached_exact.json +++ b/tests/fixtures/parity/legacy/review__get_claim_limit_reached_exact.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -126,5 +121,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_completed_assess_only.json b/tests/fixtures/parity/legacy/review__get_completed_assess_only.json index ff8ce84..da57c84 100644 --- a/tests/fixtures/parity/legacy/review__get_completed_assess_only.json +++ b/tests/fixtures/parity/legacy/review__get_completed_assess_only.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -152,5 +147,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_completed_clean.json b/tests/fixtures/parity/legacy/review__get_completed_clean.json index 3f2020c..6c37fea 100644 --- a/tests/fixtures/parity/legacy/review__get_completed_clean.json +++ b/tests/fixtures/parity/legacy/review__get_completed_clean.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -126,5 +121,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_completed_issues_all_verified.json b/tests/fixtures/parity/legacy/review__get_completed_issues_all_verified.json index 81957e3..03453bf 100644 --- a/tests/fixtures/parity/legacy/review__get_completed_issues_all_verified.json +++ b/tests/fixtures/parity/legacy/review__get_completed_issues_all_verified.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -63,10 +58,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -86,10 +81,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b79019e4", + "verification_id": "4d44dfaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", - "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "verification_url": "https://lenz.io/api/v1/verifications/4d44dfaf", + "url": "https://lenz.io/c/the-earth-is-round-4d44dfaf", "escalation": { "matched_rules": [ "verdict" @@ -139,8 +134,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "c010dca9a43543f518e49f4ec7842ceb", - "verification_id": "b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The EU AI Act took effect in March 2024.", "language": "en", "visibility": "private", @@ -156,10 +151,10 @@ "warnings": [ "w1" ], - "created_at": "2026-10-01T09:49:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "modified_at": null, - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": null @@ -196,8 +191,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "4634b89821fd877f1edf8aaeb82b7ee5", - "verification_id": "b79019e4", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "verification_id": "4d44dfaf", "claim": "The Eiffel Tower is in Berlin.", "language": "en", "visibility": "private", @@ -213,10 +208,10 @@ "warnings": [ "w1" ], - "created_at": "2026-10-01T09:49:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "modified_at": null, - "verification_url": "https://lenz.io/api/v1/verifications/b79019e4", - "url": "https://lenz.io/c/the-earth-is-round-b79019e4", + "verification_url": "https://lenz.io/api/v1/verifications/4d44dfaf", + "url": "https://lenz.io/c/the-earth-is-round-4d44dfaf", "failure": null }, "suggested_edits": null @@ -257,5 +252,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_completed_issues_full.json b/tests/fixtures/parity/legacy/review__get_completed_issues_full.json index a8c7245..7f38ed6 100644 --- a/tests/fixtures/parity/legacy/review__get_completed_issues_full.json +++ b/tests/fixtures/parity/legacy/review__get_completed_issues_full.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -63,10 +58,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -158,8 +153,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "7df4009bc27aab64ce5d5a01fbafe599", - "verification_id": "b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The EU AI Act took effect in March 2024.", "language": "en", "visibility": "private", @@ -175,10 +170,10 @@ "warnings": [ "w1" ], - "created_at": "2026-10-01T09:42:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "modified_at": null, - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": null @@ -242,7 +237,7 @@ }, "verification": { "verification_id": null, - "task_id": "5ccac77f53ff49328ec134fb29d66542", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", "claim": null, "language": null, "visibility": null, @@ -308,5 +303,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_completed_issues_view_issues.json b/tests/fixtures/parity/legacy/review__get_completed_issues_view_issues.json index c42387e..c6f0f7d 100644 --- a/tests/fixtures/parity/legacy/review__get_completed_issues_view_issues.json +++ b/tests/fixtures/parity/legacy/review__get_completed_issues_view_issues.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "issues", "status": "completed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -63,10 +58,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -129,5 +124,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_completed_positions.json b/tests/fixtures/parity/legacy/review__get_completed_positions.json index 85f1f60..be3456b 100644 --- a/tests/fixtures/parity/legacy/review__get_completed_positions.json +++ b/tests/fixtures/parity/legacy/review__get_completed_positions.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -138,5 +133,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_completed_recovered_claim.json b/tests/fixtures/parity/legacy/review__get_completed_recovered_claim.json index 9bba88a..5320c8c 100644 --- a/tests/fixtures/parity/legacy/review__get_completed_recovered_claim.json +++ b/tests/fixtures/parity/legacy/review__get_completed_recovered_claim.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -96,5 +91,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_completed_with_untraced_claim.json b/tests/fixtures/parity/legacy/review__get_completed_with_untraced_claim.json index c58b50b..b46dc3c 100644 --- a/tests/fixtures/parity/legacy/review__get_completed_with_untraced_claim.json +++ b/tests/fixtures/parity/legacy/review__get_completed_with_untraced_claim.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -138,5 +133,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_during_quick_check.json b/tests/fixtures/parity/legacy/review__get_during_quick_check.json index 7b3787b..967b16c 100644 --- a/tests/fixtures/parity/legacy/review__get_during_quick_check.json +++ b/tests/fixtures/parity/legacy/review__get_during_quick_check.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "assessing", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -84,5 +79,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_failed_every_assessment_failed.json b/tests/fixtures/parity/legacy/review__get_failed_every_assessment_failed.json index 12698ba..d117ab8 100644 --- a/tests/fixtures/parity/legacy/review__get_failed_every_assessment_failed.json +++ b/tests/fixtures/parity/legacy/review__get_failed_every_assessment_failed.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "incomplete", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -153,5 +148,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_failed_no_claim.json b/tests/fixtures/parity/legacy/review__get_failed_no_claim.json index 5d5200a..4a274ab 100644 --- a/tests/fixtures/parity/legacy/review__get_failed_no_claim.json +++ b/tests/fixtures/parity/legacy/review__get_failed_no_claim.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -64,5 +59,10 @@ "more_claims": null, "more_claim_locations": null, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_failed_no_claim_untraced.json b/tests/fixtures/parity/legacy/review__get_failed_no_claim_untraced.json index 823468b..afdea14 100644 --- a/tests/fixtures/parity/legacy/review__get_failed_no_claim_untraced.json +++ b/tests/fixtures/parity/legacy/review__get_failed_no_claim_untraced.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -64,5 +59,10 @@ "more_claims": null, "more_claim_locations": null, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_more_claims.json b/tests/fixtures/parity/legacy/review__get_more_claims.json index 5f268da..fc21fb8 100644 --- a/tests/fixtures/parity/legacy/review__get_more_claims.json +++ b/tests/fixtures/parity/legacy/review__get_more_claims.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -151,5 +146,10 @@ } ], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json index 52e321f..b3c18bb 100644 --- a/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -63,10 +58,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -116,8 +111,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "7df4009bc27aab64ce5d5a01fbafe599", - "verification_id": "b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", "language": "en", "visibility": "private", @@ -135,8 +130,8 @@ ], "created_at": "2026-10-01T23:55:00.123456+00:00", "modified_at": "2026-10-02T00:03:00.123456+00:00", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": null @@ -147,5 +142,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_same_day_hours_apart.json index 9054ce3..12724a6 100644 --- a/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/legacy/review__get_nested_verification_modified_at_same_day_hours_apart.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -63,10 +58,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "b4e2e99d", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -116,8 +111,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "7df4009bc27aab64ce5d5a01fbafe599", - "verification_id": "b4e2e99d", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", "language": "en", "visibility": "private", @@ -135,8 +130,8 @@ ], "created_at": "2026-10-01T08:00:00.123456+00:00", "modified_at": null, - "verification_url": "https://lenz.io/api/v1/verifications/b4e2e99d", - "url": "https://lenz.io/c/the-earth-is-round-b4e2e99d", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": null @@ -147,5 +142,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_policy_resolved.json b/tests/fixtures/parity/legacy/review__get_policy_resolved.json index 3116b84..20bfc3f 100644 --- a/tests/fixtures/parity/legacy/review__get_policy_resolved.json +++ b/tests/fixtures/parity/legacy/review__get_policy_resolved.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -94,5 +89,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_queued.json b/tests/fixtures/parity/legacy/review__get_queued.json index 306403b..7e2880c 100644 --- a/tests/fixtures/parity/legacy/review__get_queued.json +++ b/tests/fixtures/parity/legacy/review__get_queued.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "queued", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -58,5 +53,10 @@ "more_claims": null, "more_claim_locations": null, "more_citations": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_suggested_edits.json b/tests/fixtures/parity/legacy/review__get_suggested_edits.json index aba4758..159dab2 100644 --- a/tests/fixtures/parity/legacy/review__get_suggested_edits.json +++ b/tests/fixtures/parity/legacy/review__get_suggested_edits.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "verifying", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -63,10 +58,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "7c83247c", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", - "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -159,8 +154,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "9bca1e0819de60a750186e812dc58e2b", - "verification_id": "7c83247c", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", "language": "en", "visibility": "private", @@ -176,10 +171,10 @@ "warnings": [ "w1" ], - "created_at": "2026-10-01T09:35:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "modified_at": null, - "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", - "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": { @@ -265,5 +260,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_suggested_edits_issues_view.json b/tests/fixtures/parity/legacy/review__get_suggested_edits_issues_view.json index 1ffd8c0..a3f8882 100644 --- a/tests/fixtures/parity/legacy/review__get_suggested_edits_issues_view.json +++ b/tests/fixtures/parity/legacy/review__get_suggested_edits_issues_view.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "issues", "status": "verifying", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -63,10 +58,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "7c83247c", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/7c83247c", - "url": "https://lenz.io/c/the-earth-is-round-7c83247c", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -124,5 +119,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_url_review.json b/tests/fixtures/parity/legacy/review__get_url_review.json index ca8ddf6..cbc4a81 100644 --- a/tests/fixtures/parity/legacy/review__get_url_review.json +++ b/tests/fixtures/parity/legacy/review__get_url_review.json @@ -1,17 +1,12 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:14:00.123456Z", - "completed_at": "2026-10-01T09:21:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -102,5 +97,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__get_verifying.json b/tests/fixtures/parity/legacy/review__get_verifying.json index a388043..39f630e 100644 --- a/tests/fixtures/parity/legacy/review__get_verifying.json +++ b/tests/fixtures/parity/legacy/review__get_verifying.json @@ -1,16 +1,11 @@ { "status": 200, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "review_id": "d6b2bd72", "view": "full", "status": "verifying", "outcome": null, - "created_at": "2026-10-01T09:14:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", "completed_at": null, "language": "en", "policy": { @@ -175,5 +170,10 @@ "more_claims": [], "more_claim_locations": [], "more_citations": [] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__idempotency_body_mismatch_422.json b/tests/fixtures/parity/legacy/review__idempotency_body_mismatch_422.json index fc47586..1c526f0 100644 --- a/tests/fixtures/parity/legacy/review__idempotency_body_mismatch_422.json +++ b/tests/fixtures/parity/legacy/review__idempotency_body_mismatch_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Idempotency-Key reused with a different request body.", "code": "idempotency_body_mismatch", @@ -16,5 +11,10 @@ "msg": "Idempotency-Key reused with a different request body." } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__idempotency_conflict_409.json b/tests/fixtures/parity/legacy/review__idempotency_conflict_409.json index 8bbdff7..e0a63b2 100644 --- a/tests/fixtures/parity/legacy/review__idempotency_conflict_409.json +++ b/tests/fixtures/parity/legacy/review__idempotency_conflict_409.json @@ -1,13 +1,13 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "A review with this Idempotency-Key is still being created. Retry shortly.", "code": "idempotency_conflict", "review_id": null + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__idempotency_conflict_409_existing_review.json b/tests/fixtures/parity/legacy/review__idempotency_conflict_409_existing_review.json index edef440..e91fe17 100644 --- a/tests/fixtures/parity/legacy/review__idempotency_conflict_409_existing_review.json +++ b/tests/fixtures/parity/legacy/review__idempotency_conflict_409_existing_review.json @@ -1,13 +1,13 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "A review with this Idempotency-Key is still being created. Retry shortly.", "code": "idempotency_conflict", "review_id": "d6b2bd72" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/review__idempotent_replay_202.json b/tests/fixtures/parity/legacy/review__idempotent_replay_202.json index 6a0872b..ea99cf8 100644 --- a/tests/fixtures/parity/legacy/review__idempotent_replay_202.json +++ b/tests/fixtures/parity/legacy/review__idempotent_replay_202.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/reviews/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "review_id": "d6b2bd72", - "status": "queued" } } diff --git a/tests/fixtures/parity/legacy/review__receipt_202.json b/tests/fixtures/parity/legacy/review__receipt_202.json index 6a0872b..ea99cf8 100644 --- a/tests/fixtures/parity/legacy/review__receipt_202.json +++ b/tests/fixtures/parity/legacy/review__receipt_202.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/reviews/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "review_id": "d6b2bd72", - "status": "queued" } } diff --git a/tests/fixtures/parity/legacy/review__receipt_202_empty_webhook_url.json b/tests/fixtures/parity/legacy/review__receipt_202_empty_webhook_url.json index 6a0872b..ea99cf8 100644 --- a/tests/fixtures/parity/legacy/review__receipt_202_empty_webhook_url.json +++ b/tests/fixtures/parity/legacy/review__receipt_202_empty_webhook_url.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/reviews/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "review_id": "d6b2bd72", - "status": "queued" } } diff --git a/tests/fixtures/parity/legacy/review__receipt_202_webhook_url.json b/tests/fixtures/parity/legacy/review__receipt_202_webhook_url.json index 6a0872b..ea99cf8 100644 --- a/tests/fixtures/parity/legacy/review__receipt_202_webhook_url.json +++ b/tests/fixtures/parity/legacy/review__receipt_202_webhook_url.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/reviews/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "review_id": "d6b2bd72", - "status": "queued" } } diff --git a/tests/fixtures/parity/legacy/review__replay_later_202.json b/tests/fixtures/parity/legacy/review__replay_later_202.json index 6a0872b..ea99cf8 100644 --- a/tests/fixtures/parity/legacy/review__replay_later_202.json +++ b/tests/fixtures/parity/legacy/review__replay_later_202.json @@ -1,14 +1,14 @@ { "status": 202, + "body": { + "review_id": "d6b2bd72", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Retry-After": "20", "Location": "/api/v1/reviews/d6b2bd72", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "review_id": "d6b2bd72", - "status": "queued" } } diff --git a/tests/fixtures/parity/legacy/verify__batch_202.json b/tests/fixtures/parity/legacy/verify__batch_202.json index 7229ce4..f35e0ac 100644 --- a/tests/fixtures/parity/legacy/verify__batch_202.json +++ b/tests/fixtures/parity/legacy/verify__batch_202.json @@ -1,21 +1,21 @@ { "status": 202, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "batch_id": "7ea9cdbd4064e3cf", "items": [ { - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "claim_text": "The Earth is round." }, { - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", "claim_text": "Water boils at 100C at sea level." } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__batch_capacity_503.json b/tests/fixtures/parity/legacy/verify__batch_capacity_503.json index 342c8aa..ea99c5b 100644 --- a/tests/fixtures/parity/legacy/verify__batch_capacity_503.json +++ b/tests/fixtures/parity/legacy/verify__batch_capacity_503.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": "", "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__batch_empty_422.json b/tests/fixtures/parity/legacy/verify__batch_empty_422.json index 48a686f..8cda82f 100644 --- a/tests/fixtures/parity/legacy/verify__batch_empty_422.json +++ b/tests/fixtures/parity/legacy/verify__batch_empty_422.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "claims is required and must be non-empty." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "claims is required and must be non-empty." } } diff --git a/tests/fixtures/parity/legacy/verify__batch_idempotency_conflict_409.json b/tests/fixtures/parity/legacy/verify__batch_idempotency_conflict_409.json index 0b70d8c..ece0599 100644 --- a/tests/fixtures/parity/legacy/verify__batch_idempotency_conflict_409.json +++ b/tests/fixtures/parity/legacy/verify__batch_idempotency_conflict_409.json @@ -1,12 +1,12 @@ { "status": 409, + "body": { + "detail": "A request with this Idempotency-Key is already in progress.", + "task_id": "7cff18d" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "A request with this Idempotency-Key is already in progress.", - "task_id": "7cff18d" } } diff --git a/tests/fixtures/parity/legacy/verify__batch_item_missing_claim_422.json b/tests/fixtures/parity/legacy/verify__batch_item_missing_claim_422.json index ad1fc01..aa586cc 100644 --- a/tests/fixtures/parity/legacy/verify__batch_item_missing_claim_422.json +++ b/tests/fixtures/parity/legacy/verify__batch_item_missing_claim_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -19,5 +14,10 @@ "msg": "Field required" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__batch_no_credits_402.json b/tests/fixtures/parity/legacy/verify__batch_no_credits_402.json index 5ec2c08..3bc3035 100644 --- a/tests/fixtures/parity/legacy/verify__batch_no_credits_402.json +++ b/tests/fixtures/parity/legacy/verify__batch_no_credits_402.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Insufficient credits for batch.", "code": "no_credits", @@ -13,8 +8,13 @@ "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "requested": 1, "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 10 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__batch_partial_202.json b/tests/fixtures/parity/legacy/verify__batch_partial_202.json index 5bfc144..8b689ea 100644 --- a/tests/fixtures/parity/legacy/verify__batch_partial_202.json +++ b/tests/fixtures/parity/legacy/verify__batch_partial_202.json @@ -1,18 +1,18 @@ { "status": 202, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "batch_id": "7ea9cdbd4064e3cf", "items": [ { - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "claim_text": "First claim." } ], "partial": true + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__batch_too_many_422.json b/tests/fixtures/parity/legacy/verify__batch_too_many_422.json index a865749..95e938a 100644 --- a/tests/fixtures/parity/legacy/verify__batch_too_many_422.json +++ b/tests/fixtures/parity/legacy/verify__batch_too_many_422.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Batch size exceeds maximum of 20." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Batch size exceeds maximum of 20." } } diff --git a/tests/fixtures/parity/legacy/verify__blank_claim_422.json b/tests/fixtures/parity/legacy/verify__blank_claim_422.json index 1ebb88e..367f620 100644 --- a/tests/fixtures/parity/legacy/verify__blank_claim_422.json +++ b/tests/fixtures/parity/legacy/verify__blank_claim_422.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Text is required." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Text is required." } } diff --git a/tests/fixtures/parity/legacy/verify__capacity_503.json b/tests/fixtures/parity/legacy/verify__capacity_503.json index 342c8aa..ea99c5b 100644 --- a/tests/fixtures/parity/legacy/verify__capacity_503.json +++ b/tests/fixtures/parity/legacy/verify__capacity_503.json @@ -1,15 +1,15 @@ { "status": 503, - "headers": { - "Content-Type": "application/json", - "Retry-After": "", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Lenz is at capacity right now — please resubmit after the stated wait. Nothing was charged.", "code": "capacity", "retry_after": "", "doc_url": "https://lenz.io/docs/errors#unavailable" + }, + "headers": { + "Content-Type": "application/json", + "Retry-After": "", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__delete_200.json b/tests/fixtures/parity/legacy/verify__delete_200.json new file mode 100644 index 0000000..cddadae --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__delete_200.json @@ -0,0 +1,11 @@ +{ + "status": 200, + "body": { + "ok": true + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/verify__delete_404.json b/tests/fixtures/parity/legacy/verify__delete_404.json new file mode 100644 index 0000000..538732c --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__delete_404.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "body": { + "detail": "Not found." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/verify__delete_not_yours_404.json b/tests/fixtures/parity/legacy/verify__delete_not_yours_404.json new file mode 100644 index 0000000..538732c --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__delete_not_yours_404.json @@ -0,0 +1,11 @@ +{ + "status": 404, + "body": { + "detail": "Not found." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/verify__idempotency_body_mismatch_422.json b/tests/fixtures/parity/legacy/verify__idempotency_body_mismatch_422.json index ef04562..2425649 100644 --- a/tests/fixtures/parity/legacy/verify__idempotency_body_mismatch_422.json +++ b/tests/fixtures/parity/legacy/verify__idempotency_body_mismatch_422.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Idempotency-Key reused with a different request body." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Idempotency-Key reused with a different request body." } } diff --git a/tests/fixtures/parity/legacy/verify__idempotency_conflict_409.json b/tests/fixtures/parity/legacy/verify__idempotency_conflict_409.json index 0eee4f9..7f1510e 100644 --- a/tests/fixtures/parity/legacy/verify__idempotency_conflict_409.json +++ b/tests/fixtures/parity/legacy/verify__idempotency_conflict_409.json @@ -1,12 +1,12 @@ { "status": 409, + "body": { + "detail": "A request with this Idempotency-Key is already in progress.", + "task_id": "7cff18da2d979d6370e54a160be121ad" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "A request with this Idempotency-Key is already in progress.", - "task_id": "7cff18da2d979d6370e54a160be121ad" } } diff --git a/tests/fixtures/parity/legacy/verify__idempotency_key_replay.json b/tests/fixtures/parity/legacy/verify__idempotency_key_replay.json index b6dbf5e..1991e8a 100644 --- a/tests/fixtures/parity/legacy/verify__idempotency_key_replay.json +++ b/tests/fixtures/parity/legacy/verify__idempotency_key_replay.json @@ -1,13 +1,13 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "99a0a9ca89e1e72c" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued", - "chain_id": "78ac4e9f234ea3bd" } } diff --git a/tests/fixtures/parity/legacy/verify__implicit_dedup_200.json b/tests/fixtures/parity/legacy/verify__implicit_dedup_200.json index 011b4b9..79d39ad 100644 --- a/tests/fixtures/parity/legacy/verify__implicit_dedup_200.json +++ b/tests/fixtures/parity/legacy/verify__implicit_dedup_200.json @@ -1,12 +1,12 @@ { "status": 200, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued" } } diff --git a/tests/fixtures/parity/legacy/verify__implicit_repeat_replay.json b/tests/fixtures/parity/legacy/verify__implicit_repeat_replay.json index b6dbf5e..1991e8a 100644 --- a/tests/fixtures/parity/legacy/verify__implicit_repeat_replay.json +++ b/tests/fixtures/parity/legacy/verify__implicit_repeat_replay.json @@ -1,13 +1,13 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "99a0a9ca89e1e72c" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued", - "chain_id": "78ac4e9f234ea3bd" } } diff --git a/tests/fixtures/parity/legacy/verify__invalid_depth_422.json b/tests/fixtures/parity/legacy/verify__invalid_depth_422.json index 5c82768..6f04ccd 100644 --- a/tests/fixtures/parity/legacy/verify__invalid_depth_422.json +++ b/tests/fixtures/parity/legacy/verify__invalid_depth_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -20,5 +15,10 @@ } } ] + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__invalid_language_422.json b/tests/fixtures/parity/legacy/verify__invalid_language_422.json index 8127478..20922c8 100644 --- a/tests/fixtures/parity/legacy/verify__invalid_language_422.json +++ b/tests/fixtures/parity/legacy/verify__invalid_language_422.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Unsupported language 'xx-not-a-language'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unsupported language 'xx-not-a-language'. Supported: en, es, de, fr, it, pt, nl, sv, da, no, fi, bg. To ask for another language, contact us at https://lenz.io/contact." } } diff --git a/tests/fixtures/parity/legacy/verify__list_200.json b/tests/fixtures/parity/legacy/verify__list_200.json index c51ecc1..d7f28ec 100644 --- a/tests/fixtures/parity/legacy/verify__list_200.json +++ b/tests/fixtures/parity/legacy/verify__list_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -18,12 +13,12 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "language": "en" }, { - "verification_id": "7c83247c", + "verification_id": "4d44dfaf", "claim": "The Earth is round.", "domain": "Science", "entities": [], @@ -33,7 +28,7 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "modified_at": null, "language": "en" } @@ -41,5 +36,10 @@ "total": 2, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__list_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/verify__list_200_modified_at_crosses_midnight_by_minutes.json index bcbe8b3..e2419b1 100644 --- a/tests/fixtures/parity/legacy/verify__list_200_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/legacy/verify__list_200_modified_at_crosses_midnight_by_minutes.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -26,5 +21,10 @@ "total": 1, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__list_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/verify__list_200_modified_at_same_day_hours_apart.json index 9f2e07e..f5c69c0 100644 --- a/tests/fixtures/parity/legacy/verify__list_200_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/legacy/verify__list_200_modified_at_same_day_hours_apart.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -26,5 +21,10 @@ "total": 1, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__list_clamped_200.json b/tests/fixtures/parity/legacy/verify__list_clamped_200.json index 3d639d4..c208418 100644 --- a/tests/fixtures/parity/legacy/verify__list_clamped_200.json +++ b/tests/fixtures/parity/legacy/verify__list_clamped_200.json @@ -1,14 +1,14 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [], "total": 0, "page": 1, "page_size": 100 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__list_empty_200.json b/tests/fixtures/parity/legacy/verify__list_empty_200.json index b419316..406be8e 100644 --- a/tests/fixtures/parity/legacy/verify__list_empty_200.json +++ b/tests/fixtures/parity/legacy/verify__list_empty_200.json @@ -1,14 +1,14 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [], "total": 0, "page": 1, "page_size": 20 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__list_page2_200.json b/tests/fixtures/parity/legacy/verify__list_page2_200.json index 38ebd2f..438afdc 100644 --- a/tests/fixtures/parity/legacy/verify__list_page2_200.json +++ b/tests/fixtures/parity/legacy/verify__list_page2_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "items": [ { @@ -18,7 +13,7 @@ "key_finding": "The Earth is approximately spherical in shape.", "executive_summary": "The claim is verified.", "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "language": "en" } @@ -26,5 +21,10 @@ "total": 3, "page": 2, "page_size": 2 + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__misnamed_field_422.json b/tests/fixtures/parity/legacy/verify__misnamed_field_422.json index 98527f4..c83cdc2 100644 --- a/tests/fixtures/parity/legacy/verify__misnamed_field_422.json +++ b/tests/fixtures/parity/legacy/verify__misnamed_field_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -22,5 +17,10 @@ "unrecognized_fields": [ "statement" ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__missing_claim_422.json b/tests/fixtures/parity/legacy/verify__missing_claim_422.json index f862968..591c22f 100644 --- a/tests/fixtures/parity/legacy/verify__missing_claim_422.json +++ b/tests/fixtures/parity/legacy/verify__missing_claim_422.json @@ -1,10 +1,5 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": [ { @@ -17,5 +12,10 @@ "msg": "Field required" } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__no_credits_402.json b/tests/fixtures/parity/legacy/verify__no_credits_402.json index 32f50ac..bf3a6b1 100644 --- a/tests/fixtures/parity/legacy/verify__no_credits_402.json +++ b/tests/fixtures/parity/legacy/verify__no_credits_402.json @@ -1,10 +1,5 @@ { "status": 402, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "No remaining claim checks.", "code": "no_credits", @@ -12,8 +7,13 @@ "upgrade_url": "https://lenz.io/plans?wall=6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "wall_id": "6b86b273-ff34-4ce1-8d6b-804eff5a3f57", "remaining": 0, - "resets_at": "2026-10-01T09:14:00+00:00", + "resets_at": "2026-10-01T14:07:00+00:00", "credits_remaining": 0, "cost": 10 + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__replay_later_202.json b/tests/fixtures/parity/legacy/verify__replay_later_202.json index b6dbf5e..1991e8a 100644 --- a/tests/fixtures/parity/legacy/verify__replay_later_202.json +++ b/tests/fixtures/parity/legacy/verify__replay_later_202.json @@ -1,13 +1,13 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "99a0a9ca89e1e72c" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued", - "chain_id": "78ac4e9f234ea3bd" } } diff --git a/tests/fixtures/parity/legacy/verify__select_202.json b/tests/fixtures/parity/legacy/verify__select_202.json index 7229ce4..f35e0ac 100644 --- a/tests/fixtures/parity/legacy/verify__select_202.json +++ b/tests/fixtures/parity/legacy/verify__select_202.json @@ -1,21 +1,21 @@ { "status": 202, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "batch_id": "7ea9cdbd4064e3cf", "items": [ { - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "claim_text": "The Earth is round." }, { - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", "claim_text": "Water boils at 100C at sea level." } ] + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__select_empty_422.json b/tests/fixtures/parity/legacy/verify__select_empty_422.json index e2c29b2..a688edc 100644 --- a/tests/fixtures/parity/legacy/verify__select_empty_422.json +++ b/tests/fixtures/parity/legacy/verify__select_empty_422.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "texts is required and must be non-empty." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "texts is required and must be non-empty." } } diff --git a/tests/fixtures/parity/legacy/verify__select_invalid_selection_422.json b/tests/fixtures/parity/legacy/verify__select_invalid_selection_422.json index 637ab1f..1102de9 100644 --- a/tests/fixtures/parity/legacy/verify__select_invalid_selection_422.json +++ b/tests/fixtures/parity/legacy/verify__select_invalid_selection_422.json @@ -1,13 +1,13 @@ { "status": 422, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "Selected text was not one of the offered claims: 'The Moon is made of cheese.'", "code": "invalid_selection", "error": "invalid_selection" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__select_no_selection_pending_409.json b/tests/fixtures/parity/legacy/verify__select_no_selection_pending_409.json index 3b60350..9d0e763 100644 --- a/tests/fixtures/parity/legacy/verify__select_no_selection_pending_409.json +++ b/tests/fixtures/parity/legacy/verify__select_no_selection_pending_409.json @@ -1,13 +1,13 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This task has no pending claim selection.", "code": "no_selection_pending", "error": "no_selection_pending" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__select_too_many_422.json b/tests/fixtures/parity/legacy/verify__select_too_many_422.json index 297aef4..8cab81a 100644 --- a/tests/fixtures/parity/legacy/verify__select_too_many_422.json +++ b/tests/fixtures/parity/legacy/verify__select_too_many_422.json @@ -1,11 +1,11 @@ { "status": 422, + "body": { + "detail": "Cannot select more than 20 claims." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Cannot select more than 20 claims." } } diff --git a/tests/fixtures/parity/legacy/verify__select_unknown_task_404.json b/tests/fixtures/parity/legacy/verify__select_unknown_task_404.json index 09c1e79..d005db5 100644 --- a/tests/fixtures/parity/legacy/verify__select_unknown_task_404.json +++ b/tests/fixtures/parity/legacy/verify__select_unknown_task_404.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "detail": "Task not found." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Task not found." } } diff --git a/tests/fixtures/parity/legacy/verify__status_cancelled_after_a_while.json b/tests/fixtures/parity/legacy/verify__status_cancelled_after_a_while.json index 0350ab8..d175b8e 100644 --- a/tests/fixtures/parity/legacy/verify__status_cancelled_after_a_while.json +++ b/tests/fixtures/parity/legacy/verify__status_cancelled_after_a_while.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -13,5 +8,10 @@ "failure_class": "cancelled", "retryable": false, "docs_url": "https://lenz.io/docs/errors#cancelled" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_completed.json b/tests/fixtures/parity/legacy/verify__status_completed.json index 8e62516..2b34cd1 100644 --- a/tests/fixtures/parity/legacy/verify__status_completed.json +++ b/tests/fixtures/parity/legacy/verify__status_completed.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -30,7 +25,7 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_completed_after_a_while.json b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while.json index 8e62516..2b34cd1 100644 --- a/tests/fixtures/parity/legacy/verify__status_completed_after_a_while.json +++ b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -30,7 +25,7 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json index 3f7a898..068ec2d 100644 --- a/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json index 5a6b9fc..346ec77 100644 --- a/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/legacy/verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/verify__status_completed_modified_at_crosses_midnight_by_minutes.json index 3f7a898..068ec2d 100644 --- a/tests/fixtures/parity/legacy/verify__status_completed_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/legacy/verify__status_completed_modified_at_crosses_midnight_by_minutes.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/verify__status_completed_modified_at_same_day_hours_apart.json index 5a6b9fc..346ec77 100644 --- a/tests/fixtures/parity/legacy/verify__status_completed_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/legacy/verify__status_completed_modified_at_same_day_hours_apart.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_failed.json b/tests/fixtures/parity/legacy/verify__status_failed.json index 29f43b1..77f7bff 100644 --- a/tests/fixtures/parity/legacy/verify__status_failed.json +++ b/tests/fixtures/parity/legacy/verify__status_failed.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -13,5 +8,10 @@ "failure_class": "insufficient_evidence", "retryable": false, "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_failed_after_a_while.json b/tests/fixtures/parity/legacy/verify__status_failed_after_a_while.json index f3a344f..a0010b0 100644 --- a/tests/fixtures/parity/legacy/verify__status_failed_after_a_while.json +++ b/tests/fixtures/parity/legacy/verify__status_failed_after_a_while.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -13,5 +8,10 @@ "failure_class": "internal", "retryable": false, "docs_url": "https://lenz.io/docs/errors#internal" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_failed_after_a_while_framing.json b/tests/fixtures/parity/legacy/verify__status_failed_after_a_while_framing.json index 2f2bf0c..a0c6b65 100644 --- a/tests/fixtures/parity/legacy/verify__status_failed_after_a_while_framing.json +++ b/tests/fixtures/parity/legacy/verify__status_failed_after_a_while_framing.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -13,5 +8,10 @@ "failure_class": "upstream_unavailable", "retryable": true, "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_failed_retryable.json b/tests/fixtures/parity/legacy/verify__status_failed_retryable.json index 3451f74..05f97a9 100644 --- a/tests/fixtures/parity/legacy/verify__status_failed_retryable.json +++ b/tests/fixtures/parity/legacy/verify__status_failed_retryable.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -13,5 +8,10 @@ "failure_class": "upstream_unavailable", "retryable": true, "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_needs_input.json b/tests/fixtures/parity/legacy/verify__status_needs_input.json index 463b486..4cb32ed 100644 --- a/tests/fixtures/parity/legacy/verify__status_needs_input.json +++ b/tests/fixtures/parity/legacy/verify__status_needs_input.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "needs_input", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -20,5 +15,10 @@ } ], "hint": "The text holds several distinct claims. Send the ones to check to POST /verify/{task_id}/select." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_not_a_claim.json b/tests/fixtures/parity/legacy/verify__status_not_a_claim.json index f787d67..e900727 100644 --- a/tests/fixtures/parity/legacy/verify__status_not_a_claim.json +++ b/tests/fixtures/parity/legacy/verify__status_not_a_claim.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -14,5 +9,10 @@ "retryable": false, "docs_url": "https://lenz.io/docs/errors#invalid-input", "hint": "The input is a greeting, not a statement that can be checked. Send one factual claim, or run the text through /extract to enumerate its claims." + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_not_a_claim_after_a_while.json b/tests/fixtures/parity/legacy/verify__status_not_a_claim_after_a_while.json index ebe10ba..cd385ae 100644 --- a/tests/fixtures/parity/legacy/verify__status_not_a_claim_after_a_while.json +++ b/tests/fixtures/parity/legacy/verify__status_not_a_claim_after_a_while.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -13,5 +8,10 @@ "failure_class": "invalid_input", "retryable": false, "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_not_yours_404.json b/tests/fixtures/parity/legacy/verify__status_not_yours_404.json index 09c1e79..d005db5 100644 --- a/tests/fixtures/parity/legacy/verify__status_not_yours_404.json +++ b/tests/fixtures/parity/legacy/verify__status_not_yours_404.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "detail": "Task not found." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Task not found." } } diff --git a/tests/fixtures/parity/legacy/verify__status_older_run_completed.json b/tests/fixtures/parity/legacy/verify__status_older_run_completed.json index 8e62516..2b34cd1 100644 --- a/tests/fixtures/parity/legacy/verify__status_older_run_completed.json +++ b/tests/fixtures/parity/legacy/verify__status_older_run_completed.json @@ -1,15 +1,10 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "completed", "task_id": "7cff18da2d979d6370e54a160be121ad", "result": { - "verification_id": "4d44dfaf", + "verification_id": "68ca4aaf", "claim": "The Earth is round.", "visibility": "private", "depth": "standard", @@ -30,7 +25,7 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -95,5 +90,10 @@ "terms_version": "v1" } } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_older_run_failed_crashed.json b/tests/fixtures/parity/legacy/verify__status_older_run_failed_crashed.json index 0a8ff9f..91a9dc7 100644 --- a/tests/fixtures/parity/legacy/verify__status_older_run_failed_crashed.json +++ b/tests/fixtures/parity/legacy/verify__status_older_run_failed_crashed.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -13,5 +8,10 @@ "failure_class": "internal", "retryable": false, "docs_url": "https://lenz.io/docs/errors#internal" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_older_run_failed_insufficient_evidence.json b/tests/fixtures/parity/legacy/verify__status_older_run_failed_insufficient_evidence.json index 29f43b1..77f7bff 100644 --- a/tests/fixtures/parity/legacy/verify__status_older_run_failed_insufficient_evidence.json +++ b/tests/fixtures/parity/legacy/verify__status_older_run_failed_insufficient_evidence.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -13,5 +8,10 @@ "failure_class": "insufficient_evidence", "retryable": false, "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_older_run_in_progress.json b/tests/fixtures/parity/legacy/verify__status_older_run_in_progress.json index 8ff9472..5e5d47b 100644 --- a/tests/fixtures/parity/legacy/verify__status_older_run_in_progress.json +++ b/tests/fixtures/parity/legacy/verify__status_older_run_in_progress.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -12,8 +7,13 @@ "step": "research", "index": 2, "total": 5, - "elapsed_seconds": 2, + "elapsed_seconds": 1, "poll_after_seconds": 5 } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_processing.json b/tests/fixtures/parity/legacy/verify__status_processing.json index 8ff9472..5e5d47b 100644 --- a/tests/fixtures/parity/legacy/verify__status_processing.json +++ b/tests/fixtures/parity/legacy/verify__status_processing.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -12,8 +7,13 @@ "step": "research", "index": 2, "total": 5, - "elapsed_seconds": 2, + "elapsed_seconds": 1, "poll_after_seconds": 5 } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_processing_after_a_while.json b/tests/fixtures/parity/legacy/verify__status_processing_after_a_while.json index 077dee8..e0638f1 100644 --- a/tests/fixtures/parity/legacy/verify__status_processing_after_a_while.json +++ b/tests/fixtures/parity/legacy/verify__status_processing_after_a_while.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -12,8 +7,13 @@ "step": "adjudication", "index": 4, "total": 5, - "elapsed_seconds": 2, + "elapsed_seconds": 1, "poll_after_seconds": 5 } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_task_stuck.json b/tests/fixtures/parity/legacy/verify__status_task_stuck.json index 2504c91..383a365 100644 --- a/tests/fixtures/parity/legacy/verify__status_task_stuck.json +++ b/tests/fixtures/parity/legacy/verify__status_task_stuck.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "status": "failed", "task_id": "7cff18da2d979d6370e54a160be121ad", @@ -13,5 +8,10 @@ "failure_class": "upstream_unavailable", "retryable": true, "docs_url": "https://lenz.io/docs/errors#upstream-unavailable" + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__status_unknown_404.json b/tests/fixtures/parity/legacy/verify__status_unknown_404.json index 09c1e79..d005db5 100644 --- a/tests/fixtures/parity/legacy/verify__status_unknown_404.json +++ b/tests/fixtures/parity/legacy/verify__status_unknown_404.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "detail": "Task not found." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Task not found." } } diff --git a/tests/fixtures/parity/legacy/verify__submit_202.json b/tests/fixtures/parity/legacy/verify__submit_202.json index b6dbf5e..1991e8a 100644 --- a/tests/fixtures/parity/legacy/verify__submit_202.json +++ b/tests/fixtures/parity/legacy/verify__submit_202.json @@ -1,13 +1,13 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "99a0a9ca89e1e72c" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued", - "chain_id": "78ac4e9f234ea3bd" } } diff --git a/tests/fixtures/parity/legacy/verify__submit_202_options.json b/tests/fixtures/parity/legacy/verify__submit_202_options.json index b6dbf5e..1991e8a 100644 --- a/tests/fixtures/parity/legacy/verify__submit_202_options.json +++ b/tests/fixtures/parity/legacy/verify__submit_202_options.json @@ -1,13 +1,13 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "99a0a9ca89e1e72c" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued", - "chain_id": "78ac4e9f234ea3bd" } } diff --git a/tests/fixtures/parity/legacy/verify__submit_202_text_alias.json b/tests/fixtures/parity/legacy/verify__submit_202_text_alias.json index b6dbf5e..1991e8a 100644 --- a/tests/fixtures/parity/legacy/verify__submit_202_text_alias.json +++ b/tests/fixtures/parity/legacy/verify__submit_202_text_alias.json @@ -1,13 +1,13 @@ { "status": 202, + "body": { + "task_id": "7cff18da2d979d6370e54a160be121ad", + "status": "queued", + "chain_id": "99a0a9ca89e1e72c" + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "task_id": "7cff18da2d979d6370e54a160be121ad", - "status": "queued", - "chain_id": "78ac4e9f234ea3bd" } } diff --git a/tests/fixtures/parity/legacy/verify__unauthenticated_401.json b/tests/fixtures/parity/legacy/verify__unauthenticated_401.json index 8dd2fb4..54ec0b6 100644 --- a/tests/fixtures/parity/legacy/verify__unauthenticated_401.json +++ b/tests/fixtures/parity/legacy/verify__unauthenticated_401.json @@ -1,11 +1,11 @@ { "status": 401, + "body": { + "detail": "Unauthorized" + }, "headers": { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Unauthorized" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_200.json b/tests/fixtures/parity/legacy/verify__verification_200.json index b4a8eae..50599ee 100644 --- a/tests/fixtures/parity/legacy/verify__verification_200.json +++ b/tests/fixtures/parity/legacy/verify__verification_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,7 +22,7 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_200_covered.json b/tests/fixtures/parity/legacy/verify__verification_200_covered.json index 5ff9574..fa6aef7 100644 --- a/tests/fixtures/parity/legacy/verify__verification_200_covered.json +++ b/tests/fixtures/parity/legacy/verify__verification_200_covered.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,7 +22,7 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -81,13 +76,18 @@ "coverage": { "status": "covered", "reasons": [], - "certificate_id": "def7232d27eda03cf261569aee9948c5", - "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "certificate_id": "95b0f3dd008b46846b6dd6b15099e2b3", + "certificate_url": "https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3", "as_of": "2026-03-10T12:01:30+00:00", "currency": "EUR", "cap": 10000, "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_crosses_midnight_by_minutes.json index c57efcb..2376a58 100644 --- a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_crosses_midnight_by_minutes.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_null.json b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_null.json index b4a8eae..50599ee 100644 --- a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_null.json +++ b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_null.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,7 +22,7 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_same_day_hours_apart.json index 4480b71..47e455c 100644 --- a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_same_day_hours_apart.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_set.json b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_set.json index c57efcb..2376a58 100644 --- a/tests/fixtures/parity/legacy/verify__verification_200_modified_at_set.json +++ b/tests/fixtures/parity/legacy/verify__verification_200_modified_at_set.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_200_result_json_conclusion_only.json b/tests/fixtures/parity/legacy/verify__verification_200_result_json_conclusion_only.json index 86594fb..b5cdcd6 100644 --- a/tests/fixtures/parity/legacy/verify__verification_200_result_json_conclusion_only.json +++ b/tests/fixtures/parity/legacy/verify__verification_200_result_json_conclusion_only.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -20,7 +15,7 @@ "executive_summary": "The claim is verified.", "warnings": [], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [], "audit": { @@ -52,5 +47,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_200_result_json_empty.json b/tests/fixtures/parity/legacy/verify__verification_200_result_json_empty.json index 86594fb..b5cdcd6 100644 --- a/tests/fixtures/parity/legacy/verify__verification_200_result_json_empty.json +++ b/tests/fixtures/parity/legacy/verify__verification_200_result_json_empty.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -20,7 +15,7 @@ "executive_summary": "The claim is verified.", "warnings": [], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [], "audit": { @@ -52,5 +47,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_200_result_json_old_shape_strings.json b/tests/fixtures/parity/legacy/verify__verification_200_result_json_old_shape_strings.json index 34ae356..3250756 100644 --- a/tests/fixtures/parity/legacy/verify__verification_200_result_json_old_shape_strings.json +++ b/tests/fixtures/parity/legacy/verify__verification_200_result_json_old_shape_strings.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -20,7 +15,7 @@ "executive_summary": "The claim is verified.", "warnings": [], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -68,5 +63,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_404.json b/tests/fixtures/parity/legacy/verify__verification_404.json index 3bf3204..538732c 100644 --- a/tests/fixtures/parity/legacy/verify__verification_404.json +++ b/tests/fixtures/parity/legacy/verify__verification_404.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "detail": "Not found." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Not found." } } diff --git a/tests/fixtures/parity/legacy/verify__verification_by_task_id_200.json b/tests/fixtures/parity/legacy/verify__verification_by_task_id_200.json index b4a8eae..50599ee 100644 --- a/tests/fixtures/parity/legacy/verify__verification_by_task_id_200.json +++ b/tests/fixtures/parity/legacy/verify__verification_by_task_id_200.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,7 +22,7 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_failed_409.json b/tests/fixtures/parity/legacy/verify__verification_failed_409.json index fc6de0a..fdb3f4f 100644 --- a/tests/fixtures/parity/legacy/verify__verification_failed_409.json +++ b/tests/fixtures/parity/legacy/verify__verification_failed_409.json @@ -1,10 +1,5 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This check failed and has no result.", "code": "verification_failed", @@ -15,5 +10,10 @@ "failure_class": "insufficient_evidence", "retryable": false, "docs_url": "https://lenz.io/docs/errors#insufficient-evidence" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_failed_409_not_a_claim_after_a_while.json b/tests/fixtures/parity/legacy/verify__verification_failed_409_not_a_claim_after_a_while.json index d0c0aa6..41c53e8 100644 --- a/tests/fixtures/parity/legacy/verify__verification_failed_409_not_a_claim_after_a_while.json +++ b/tests/fixtures/parity/legacy/verify__verification_failed_409_not_a_claim_after_a_while.json @@ -1,10 +1,5 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This check failed and has no result.", "code": "verification_failed", @@ -15,5 +10,10 @@ "failure_class": "invalid_input", "retryable": false, "docs_url": "https://lenz.io/docs/errors#invalid-input" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_not_ready_409.json b/tests/fixtures/parity/legacy/verify__verification_not_ready_409.json index d5ace3f..dae092f 100644 --- a/tests/fixtures/parity/legacy/verify__verification_not_ready_409.json +++ b/tests/fixtures/parity/legacy/verify__verification_not_ready_409.json @@ -1,15 +1,15 @@ { "status": 409, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This check is still running.", "code": "verification_not_ready", "status": "processing", "task_id": "7cff18da2d979d6370e54a160be121ad", "hint": "Poll GET /verify/status/7cff18da2d979d6370e54a160be121ad until it completes, then read its result." + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_not_yours_404.json b/tests/fixtures/parity/legacy/verify__verification_not_yours_404.json index 3bf3204..538732c 100644 --- a/tests/fixtures/parity/legacy/verify__verification_not_yours_404.json +++ b/tests/fixtures/parity/legacy/verify__verification_not_yours_404.json @@ -1,11 +1,11 @@ { "status": 404, + "body": { + "detail": "Not found." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Not found." } } diff --git a/tests/fixtures/parity/legacy/verify__verification_public_anonymous.json b/tests/fixtures/parity/legacy/verify__verification_public_anonymous.json index 6f459a1..2500a41 100644 --- a/tests/fixtures/parity/legacy/verify__verification_public_anonymous.json +++ b/tests/fixtures/parity/legacy/verify__verification_public_anonymous.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,7 +22,7 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -79,5 +74,10 @@ }, "language": "en", "coverage": null + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_public_of_another_user.json b/tests/fixtures/parity/legacy/verify__verification_public_of_another_user.json index b81a9a7..1bd991f 100644 --- a/tests/fixtures/parity/legacy/verify__verification_public_of_another_user.json +++ b/tests/fixtures/parity/legacy/verify__verification_public_of_another_user.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,7 +22,7 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_unknown_task_404.json b/tests/fixtures/parity/legacy/verify__verification_unknown_task_404.json index cfc00c7..379c918 100644 --- a/tests/fixtures/parity/legacy/verify__verification_unknown_task_404.json +++ b/tests/fixtures/parity/legacy/verify__verification_unknown_task_404.json @@ -1,12 +1,12 @@ { "status": 404, + "body": { + "detail": "Not found.", + "hint": "Unknown id. If this is a task_id, poll GET /verify/status/dddddddddddddddddddddddddddddddd for its status." + }, "headers": { "Content-Type": "application/json", "Cache-Control": "no-store", "Vary": "origin" - }, - "body": { - "detail": "Not found.", - "hint": "Unknown id. If this is a task_id, poll GET /verify/status/dddddddddddddddddddddddddddddddd for its status." } } diff --git a/tests/fixtures/parity/legacy/verify__verification_zero_retention_expired_410.json b/tests/fixtures/parity/legacy/verify__verification_zero_retention_expired_410.json index 010b258..924d468 100644 --- a/tests/fixtures/parity/legacy/verify__verification_zero_retention_expired_410.json +++ b/tests/fixtures/parity/legacy/verify__verification_zero_retention_expired_410.json @@ -1,13 +1,13 @@ { "status": 410, - "headers": { - "Content-Type": "application/json", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "detail": "This verification is no longer available: its account removes verifications after a set period.", "code": "purged", "purged_at": "2026-10-01T09:07:00.123456+00:00" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__verification_zero_retention_served.json b/tests/fixtures/parity/legacy/verify__verification_zero_retention_served.json index 21c8d25..89895ad 100644 --- a/tests/fixtures/parity/legacy/verify__verification_zero_retention_served.json +++ b/tests/fixtures/parity/legacy/verify__verification_zero_retention_served.json @@ -1,10 +1,5 @@ { "status": 200, - "headers": { - "Content-Type": "application/json; charset=utf-8", - "Cache-Control": "no-store", - "Vary": "origin" - }, "body": { "verification_id": "68ca4aaf", "claim": "The Earth is round.", @@ -27,7 +22,7 @@ "Relies on limited sources" ], "suggested_rewrite": null, - "created_at": "2026-10-01T09:14:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -91,5 +86,10 @@ "aggregate": 500000, "terms_version": "v1" } + }, + "headers": { + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "no-store", + "Vary": "origin" } } diff --git a/tests/fixtures/parity/legacy/verify__webhook_secret_missing_422.json b/tests/fixtures/parity/legacy/verify__webhook_secret_missing_422.json new file mode 100644 index 0000000..bae889d --- /dev/null +++ b/tests/fixtures/parity/legacy/verify__webhook_secret_missing_422.json @@ -0,0 +1,12 @@ +{ + "status": 422, + "body": { + "detail": "webhook_url was supplied but this API key has no HMAC secret. Generate one at https://lenz.io/api-credentials (Webhooks panel) before submitting webhook-delivered calls.", + "code": "webhook_secret_missing" + }, + "headers": { + "Content-Type": "application/json", + "Cache-Control": "no-store", + "Vary": "origin" + } +} diff --git a/tests/fixtures/parity/legacy/webhook__certificate_timestamped.json b/tests/fixtures/parity/legacy/webhook__certificate_timestamped.json index a47b14c..eaeb5fb 100644 --- a/tests/fixtures/parity/legacy/webhook__certificate_timestamped.json +++ b/tests/fixtures/parity/legacy/webhook__certificate_timestamped.json @@ -1,10 +1,9 @@ { "status": 200, - "headers": {}, "body": { "event": "certificate.timestamped", "verification_id": "68ca4aaf", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "batch_id": null, "status": "completed", "result": null, @@ -12,8 +11,8 @@ "coverage": { "status": "covered", "reasons": [], - "certificate_id": "def7232d27eda03cf261569aee9948c5", - "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "certificate_id": "95b0f3dd008b46846b6dd6b15099e2b3", + "certificate_url": "https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3", "as_of": "2026-09-03T10:00:00+00:00", "currency": "EUR", "cap": 10000, @@ -22,6 +21,7 @@ }, "error": null, "attempt": 1, - "delivered_at": "2026-10-01T09:28:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__certificate_timestamped_review_child.json b/tests/fixtures/parity/legacy/webhook__certificate_timestamped_review_child.json index 028efa3..6c67b46 100644 --- a/tests/fixtures/parity/legacy/webhook__certificate_timestamped_review_child.json +++ b/tests/fixtures/parity/legacy/webhook__certificate_timestamped_review_child.json @@ -1,10 +1,9 @@ { "status": 200, - "headers": {}, "body": { "event": "certificate.timestamped", "verification_id": "68ca4aaf", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "batch_id": null, "status": "completed", "result": null, @@ -12,8 +11,8 @@ "coverage": { "status": "covered", "reasons": [], - "certificate_id": "def7232d27eda03cf261569aee9948c5", - "certificate_url": "https://lenz.io/certificate/def7232d27eda03cf261569aee9948c5", + "certificate_id": "95b0f3dd008b46846b6dd6b15099e2b3", + "certificate_url": "https://lenz.io/certificate/95b0f3dd008b46846b6dd6b15099e2b3", "as_of": "2026-09-03T10:00:00+00:00", "currency": "EUR", "cap": 10000, @@ -23,6 +22,7 @@ "error": null, "review_id": "d6b2bd72", "attempt": 1, - "delivered_at": "2026-10-01T09:28:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__citecheck_completed.json b/tests/fixtures/parity/legacy/webhook__citecheck_completed.json index 447a098..b8a79a6 100644 --- a/tests/fixtures/parity/legacy/webhook__citecheck_completed.json +++ b/tests/fixtures/parity/legacy/webhook__citecheck_completed.json @@ -1,18 +1,17 @@ { "status": 200, - "headers": {}, "body": { "event": "citecheck.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "citecheck_id": "98c0e7d5", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "citecheck_id": "8eb49302", + "task_id": "7cff18da2d979d6370e54a160be121ad", "status": "completed", "citecheck": { - "citecheck_id": "98c0e7d5", + "citecheck_id": "8eb49302", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:28:00.123456Z", - "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -129,6 +128,7 @@ "more_citations": [] }, "attempt": 1, - "delivered_at": "2026-10-01T09:42:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__citecheck_failed.json b/tests/fixtures/parity/legacy/webhook__citecheck_failed.json index 19627f2..7738080 100644 --- a/tests/fixtures/parity/legacy/webhook__citecheck_failed.json +++ b/tests/fixtures/parity/legacy/webhook__citecheck_failed.json @@ -1,18 +1,17 @@ { "status": 200, - "headers": {}, "body": { "event": "citecheck.failed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "citecheck_id": "98c0e7d5", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "citecheck_id": "8eb49302", + "task_id": "7cff18da2d979d6370e54a160be121ad", "status": "failed", "citecheck": { - "citecheck_id": "98c0e7d5", + "citecheck_id": "8eb49302", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:28:00.123456Z", - "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "poll_after_seconds": null, "policy": { @@ -42,6 +41,7 @@ "more_citations": null }, "attempt": 1, - "delivered_at": "2026-10-01T09:42:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__review_completed.json b/tests/fixtures/parity/legacy/webhook__review_completed.json index 1149eea..ea72c1c 100644 --- a/tests/fixtures/parity/legacy/webhook__review_completed.json +++ b/tests/fixtures/parity/legacy/webhook__review_completed.json @@ -1,19 +1,18 @@ { "status": 200, - "headers": {}, "body": { "event": "review.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "review_id": "8cb2f001", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "review_id": "d6b2bd72", + "task_id": "7cff18da2d979d6370e54a160be121ad", "status": "completed", "review": { - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "issues_found", - "created_at": "2026-10-01T09:28:00.123456Z", - "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -65,10 +64,10 @@ "verdict": "False", "confidence": "high", "source": "verification", - "verification_id": "8ceed6f0", + "verification_id": "68ca4aaf", "verification_status": "completed", - "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", - "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "escalation": { "matched_rules": [ "verdict" @@ -118,8 +117,8 @@ "verification": { "status": "completed", "content_status": "available", - "task_id": "5ccac77f53ff49328ec134fb29d66542", - "verification_id": "8ceed6f0", + "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "verification_id": "68ca4aaf", "claim": "The Eiffel Tower is in Berlin.", "language": "en", "visibility": "private", @@ -135,10 +134,10 @@ "warnings": [ "w1" ], - "created_at": "2026-10-01T09:56:00.123456+00:00", + "created_at": "2026-10-01T09:14:00.123456+00:00", "modified_at": null, - "verification_url": "https://lenz.io/api/v1/verifications/8ceed6f0", - "url": "https://lenz.io/c/the-earth-is-round-8ceed6f0", + "verification_url": "https://lenz.io/api/v1/verifications/68ca4aaf", + "url": "https://lenz.io/c/the-earth-is-round-68ca4aaf", "failure": null }, "suggested_edits": null @@ -151,6 +150,7 @@ "more_citations": [] }, "attempt": 1, - "delivered_at": "2026-10-01T10:03:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__review_completed_key_default_url.json b/tests/fixtures/parity/legacy/webhook__review_completed_key_default_url.json index 35c4a30..7c98f76 100644 --- a/tests/fixtures/parity/legacy/webhook__review_completed_key_default_url.json +++ b/tests/fixtures/parity/legacy/webhook__review_completed_key_default_url.json @@ -1,19 +1,18 @@ { "status": 200, - "headers": {}, "body": { "event": "review.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "review_id": "8cb2f001", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "review_id": "d6b2bd72", + "task_id": "7cff18da2d979d6370e54a160be121ad", "status": "completed", "review": { - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "view": "full", "status": "completed", "outcome": "clean", - "created_at": "2026-10-01T09:28:00.123456Z", - "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -100,6 +99,7 @@ "more_citations": [] }, "attempt": 1, - "delivered_at": "2026-10-01T09:42:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__review_completed_oversized_rebuilt.json b/tests/fixtures/parity/legacy/webhook__review_completed_oversized_rebuilt.json index 6248eaf..cd09384 100644 --- a/tests/fixtures/parity/legacy/webhook__review_completed_oversized_rebuilt.json +++ b/tests/fixtures/parity/legacy/webhook__review_completed_oversized_rebuilt.json @@ -1,11 +1,11 @@ { "status": 200, - "headers": {}, "body": { "event": "review.completed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "review_id": "8cb2f001", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "review_id": "d6b2bd72", + "task_id": "7cff18da2d979d6370e54a160be121ad", "status": "completed" - } + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__review_failed.json b/tests/fixtures/parity/legacy/webhook__review_failed.json index 294d967..364b930 100644 --- a/tests/fixtures/parity/legacy/webhook__review_failed.json +++ b/tests/fixtures/parity/legacy/webhook__review_failed.json @@ -1,19 +1,18 @@ { "status": 200, - "headers": {}, "body": { "event": "review.failed", "event_id": "evt_09301870aba4e8f6ae33ff60", - "review_id": "8cb2f001", - "task_id": "13610f0b64b63e006dc66364e0e82c85", + "review_id": "d6b2bd72", + "task_id": "7cff18da2d979d6370e54a160be121ad", "status": "failed", "review": { - "review_id": "8cb2f001", + "review_id": "d6b2bd72", "view": "full", "status": "failed", "outcome": "unchecked", - "created_at": "2026-10-01T09:28:00.123456Z", - "completed_at": "2026-10-01T09:35:00.123456Z", + "created_at": "2026-10-01T09:07:00.123456Z", + "completed_at": "2026-10-01T10:07:00.123456Z", "language": "en", "policy": { "verdicts": [ @@ -68,6 +67,7 @@ "more_citations": null }, "attempt": 1, - "delivered_at": "2026-10-01T09:42:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__test_fire.json b/tests/fixtures/parity/legacy/webhook__test_fire.json new file mode 100644 index 0000000..131b2f2 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__test_fire.json @@ -0,0 +1,17 @@ +{ + "status": 200, + "body": { + "attempt": 1, + "batch_id": null, + "coverage": null, + "delivered_at": "2026-10-01T11:07:00.123456+00:00", + "error": null, + "event": "webhook.test", + "needs_input": null, + "result": null, + "status": "test", + "task_id": "test_7cff18da2d979d63", + "verification_id": null + }, + "headers": {} +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_completed.json b/tests/fixtures/parity/legacy/webhook__verification_completed.json index 68b9dbb..04dae69 100644 --- a/tests/fixtures/parity/legacy/webhook__verification_completed.json +++ b/tests/fixtures/parity/legacy/webhook__verification_completed.json @@ -1,10 +1,9 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.completed", "verification_id": "68ca4aaf", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "batch_id": null, "status": "completed", "result": { @@ -33,7 +32,7 @@ "Only two sources were found." ], "suggested_rewrite": "The Eiffel Tower is in Paris.", - "created_at": "2026-10-01T09:21:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -102,6 +101,7 @@ "coverage": null, "error": null, "attempt": 1, - "delivered_at": "2026-10-01T09:28:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__verification_completed_in_batch.json b/tests/fixtures/parity/legacy/webhook__verification_completed_in_batch.json index be55b0a..efa7cc2 100644 --- a/tests/fixtures/parity/legacy/webhook__verification_completed_in_batch.json +++ b/tests/fixtures/parity/legacy/webhook__verification_completed_in_batch.json @@ -1,11 +1,10 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.completed", "verification_id": "68ca4aaf", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", - "batch_id": "4ee0c3aa1b671eaa", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "batch_id": "7ea9cdbd4064e3cf", "status": "completed", "result": { "verification_id": "68ca4aaf", @@ -33,7 +32,7 @@ "Only two sources were found." ], "suggested_rewrite": "The Eiffel Tower is in Paris.", - "created_at": "2026-10-01T09:28:00.123456+00:00", + "created_at": "2026-10-01T09:07:00.123456+00:00", "modified_at": null, "sources": [ { @@ -102,6 +101,7 @@ "coverage": null, "error": null, "attempt": 1, - "delivered_at": "2026-10-01T09:35:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json b/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json index c9af648..558176e 100644 --- a/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json +++ b/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_crosses_midnight_by_minutes.json @@ -1,10 +1,9 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.completed", "verification_id": "68ca4aaf", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "batch_id": null, "status": "completed", "result": { @@ -102,6 +101,7 @@ "coverage": null, "error": null, "attempt": 1, - "delivered_at": "2026-10-01T09:35:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_same_day_hours_apart.json b/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_same_day_hours_apart.json index 6d2f10a..dee4598 100644 --- a/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_same_day_hours_apart.json +++ b/tests/fixtures/parity/legacy/webhook__verification_completed_modified_at_same_day_hours_apart.json @@ -1,10 +1,9 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.completed", "verification_id": "68ca4aaf", - "task_id": "0b92b443eb69b9c71434fdc64f2ca8be", + "task_id": "7cff18da2d979d6370e54a160be121ad", "batch_id": null, "status": "completed", "result": { @@ -102,6 +101,7 @@ "coverage": null, "error": null, "attempt": 1, - "delivered_at": "2026-10-01T09:28:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__verification_completed_sparse_result.json b/tests/fixtures/parity/legacy/webhook__verification_completed_sparse_result.json new file mode 100644 index 0000000..643b479 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_completed_sparse_result.json @@ -0,0 +1,52 @@ +{ + "status": 200, + "body": { + "event": "verification.completed", + "verification_id": "68ca4aaf", + "task_id": "7cff18da2d979d6370e54a160be121ad", + "batch_id": null, + "status": "completed", + "result": { + "verification_id": "68ca4aaf", + "claim": "The Eiffel Tower is in Berlin.", + "visibility": "private", + "depth": "standard", + "domain": "", + "entities": [], + "presumed_intent": "", + "verdict": "", + "confidence": "low", + "lenz_score": null, + "key_finding": "", + "executive_summary": "", + "warnings": [], + "suggested_rewrite": null, + "created_at": "", + "modified_at": null, + "sources": [], + "audit": { + "adjudication_summary": "", + "assessments": [], + "debate_pro": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "debate_con": { + "role": "", + "argument": "", + "rebuttal": "" + }, + "panel_agreement": "" + }, + "language": "en", + "coverage": null + }, + "needs_input": null, + "coverage": null, + "error": null, + "attempt": 1, + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_failed_error_none.json b/tests/fixtures/parity/legacy/webhook__verification_failed_error_none.json new file mode 100644 index 0000000..6647535 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_failed_error_none.json @@ -0,0 +1,19 @@ +{ + "status": 200, + "body": { + "event": "verification.failed", + "verification_id": null, + "task_id": "7cff18da2d979d6370e54a160be121ad", + "batch_id": null, + "status": "failed", + "result": null, + "needs_input": null, + "coverage": null, + "error": null, + "failure_class": "internal", + "retryable": false, + "attempt": 1, + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_failed_insufficient_evidence.json b/tests/fixtures/parity/legacy/webhook__verification_failed_insufficient_evidence.json index e44f526..ecfcdbd 100644 --- a/tests/fixtures/parity/legacy/webhook__verification_failed_insufficient_evidence.json +++ b/tests/fixtures/parity/legacy/webhook__verification_failed_insufficient_evidence.json @@ -1,6 +1,5 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.failed", "verification_id": null, @@ -14,6 +13,7 @@ "failure_class": "insufficient_evidence", "retryable": false, "attempt": 1, - "delivered_at": "2026-10-01T09:14:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__verification_failed_not_a_claim.json b/tests/fixtures/parity/legacy/webhook__verification_failed_not_a_claim.json index d27f1f1..5dc356d 100644 --- a/tests/fixtures/parity/legacy/webhook__verification_failed_not_a_claim.json +++ b/tests/fixtures/parity/legacy/webhook__verification_failed_not_a_claim.json @@ -1,6 +1,5 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.failed", "verification_id": null, @@ -14,6 +13,7 @@ "failure_class": "invalid_input", "retryable": false, "attempt": 1, - "delivered_at": "2026-10-01T09:14:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__verification_failed_upstream_unavailable.json b/tests/fixtures/parity/legacy/webhook__verification_failed_upstream_unavailable.json index 14ba36a..867b62b 100644 --- a/tests/fixtures/parity/legacy/webhook__verification_failed_upstream_unavailable.json +++ b/tests/fixtures/parity/legacy/webhook__verification_failed_upstream_unavailable.json @@ -1,6 +1,5 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.failed", "verification_id": null, @@ -14,6 +13,7 @@ "failure_class": "upstream_unavailable", "retryable": true, "attempt": 1, - "delivered_at": "2026-10-01T09:14:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/legacy/webhook__verification_needs_input_hint_none.json b/tests/fixtures/parity/legacy/webhook__verification_needs_input_hint_none.json new file mode 100644 index 0000000..0a349f3 --- /dev/null +++ b/tests/fixtures/parity/legacy/webhook__verification_needs_input_hint_none.json @@ -0,0 +1,27 @@ +{ + "status": 200, + "body": { + "event": "verification.needs_input", + "verification_id": null, + "task_id": "7cff18da2d979d6370e54a160be121ad", + "batch_id": null, + "status": "needs_input", + "result": null, + "needs_input": { + "reason": "multi_claim", + "claims": [ + { + "text": "The Eiffel Tower is in Berlin.", + "domain": "" + } + ], + "hint": null + }, + "error": null, + "coverage": null, + "review_id": null, + "attempt": 1, + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} +} diff --git a/tests/fixtures/parity/legacy/webhook__verification_needs_input_multi_claim.json b/tests/fixtures/parity/legacy/webhook__verification_needs_input_multi_claim.json index 4d08431..9395c84 100644 --- a/tests/fixtures/parity/legacy/webhook__verification_needs_input_multi_claim.json +++ b/tests/fixtures/parity/legacy/webhook__verification_needs_input_multi_claim.json @@ -1,6 +1,5 @@ { "status": 200, - "headers": {}, "body": { "event": "verification.needs_input", "verification_id": null, @@ -25,6 +24,7 @@ "coverage": null, "error": null, "attempt": 1, - "delivered_at": "2026-10-01T09:14:00.123456+00:00" - } + "delivered_at": "2026-10-01T11:07:00.123456+00:00" + }, + "headers": {} } diff --git a/tests/fixtures/parity/pickles.json b/tests/fixtures/parity/pickles.json new file mode 100644 index 0000000..cf1551e --- /dev/null +++ b/tests/fixtures/parity/pickles.json @@ -0,0 +1,156 @@ +{ + "account__library_empty.json": "gASVuQAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwLTGlicmFyeUxpc3SUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwFaXRlbXOUXZSMBXRvdGFslEsAjARwYWdllEsBjAlwYWdlX3NpemWUSxR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgKaAtoCWgHkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViLg==", + "account__library_item_modified_at_crosses_midnight_by_minutes.json": "gASVdwIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwLTGlicmFyeUxpc3SUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwFaXRlbXOUXZRoAIwLTGlicmFyeUl0ZW2Uk5QpgZR9lChoBX2UKIwPdmVyaWZpY2F0aW9uX2lklIwINjhjYTRhYWaUjAVjbGFpbZSMEEEgbGlicmFyeSBjbGFpbS6UjAZkb21haW6UjACUjAhlbnRpdGllc5RdlIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwDbG93lIwKbGVuel9zY29yZZRLCowLa2V5X2ZpbmRpbmeUjC5UaGUgRWFydGggaXMgYXBwcm94aW1hdGVseSBzcGhlcmljYWwgaW4gc2hhcGUulIwRZXhlY3V0aXZlX3N1bW1hcnmUjBZUaGUgY2xhaW0gaXMgdmVyaWZpZWQulIwRc3VnZ2VzdGVkX3Jld3JpdGWUTowKY3JlYXRlZF9hdJSMIDIwMjYtMTAtMDFUMjM6NTU6MDAuMTIzNDU2KzAwOjAwlIwLbW9kaWZpZWRfYXSUjCAyMDI2LTEwLTAyVDAwOjAzOjAwLjEyMzQ1NiswMDowMJSMCGxhbmd1YWdllIwCZW6UdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoEGgOaBRoGGggaBJoFmgkaCJoHWgaaBtoH5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMBXRvdGFslEsBjARwYWdllEsBjAlwYWdlX3NpemWUSxR1aCZ9lGgoj5QoaCxoLWgraAeQaCpOdWIu", + "account__library_item_modified_at_same_day_hours_apart.json": "gASVVQIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwLTGlicmFyeUxpc3SUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwFaXRlbXOUXZRoAIwLTGlicmFyeUl0ZW2Uk5QpgZR9lChoBX2UKIwPdmVyaWZpY2F0aW9uX2lklIwINjhjYTRhYWaUjAVjbGFpbZSMEEEgbGlicmFyeSBjbGFpbS6UjAZkb21haW6UjACUjAhlbnRpdGllc5RdlIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwDbG93lIwKbGVuel9zY29yZZRLCowLa2V5X2ZpbmRpbmeUjC5UaGUgRWFydGggaXMgYXBwcm94aW1hdGVseSBzcGhlcmljYWwgaW4gc2hhcGUulIwRZXhlY3V0aXZlX3N1bW1hcnmUjBZUaGUgY2xhaW0gaXMgdmVyaWZpZWQulIwRc3VnZ2VzdGVkX3Jld3JpdGWUTowKY3JlYXRlZF9hdJSMIDIwMjYtMTAtMDFUMDg6MDA6MDAuMTIzNDU2KzAwOjAwlIwLbW9kaWZpZWRfYXSUTowIbGFuZ3VhZ2WUjAJlbpR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgQaA5oFGgYaCBoEmgWaCNoImgdaBpoG2gfkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViYYwFdG90YWyUSwGMBHBhZ2WUSwGMCXBhZ2Vfc2l6ZZRLFHVoJX2UaCePlChoK2gsaCpoB5BoKU51Yi4=", + "account__library_items.json": "gASVWQQAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwLTGlicmFyeUxpc3SUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwFaXRlbXOUXZQoaACMC0xpYnJhcnlJdGVtlJOUKYGUfZQoaAV9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBBMaWJyYXJ5IGNsYWltIDAulIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UjAd2ZXJkaWN0lIwEVHJ1ZZSMCmNvbmZpZGVuY2WUjANsb3eUjApsZW56X3Njb3JllEsKjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjBFzdWdnZXN0ZWRfcmV3cml0ZZROjApjcmVhdGVkX2F0lIwgMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTYrMDA6MDCUjAttb2RpZmllZF9hdJROjAhsYW5ndWFnZZSMAmVulHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBBoDmgUaBhoIGgSaBZoI2giaB1oGmgbaB+QjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJoCimBlH2UKGgFfZQoaA6MCDRkNDRkZmFmlGgQjBBMaWJyYXJ5IGNsYWltIDEulGgSjAdTY2llbmNllGgUXZRoFowEVHJ1ZZRoGIwDbG93lGgaSwpoG4wuVGhlIEVhcnRoIGlzIGFwcHJveGltYXRlbHkgc3BoZXJpY2FsIGluIHNoYXBlLpRoHYwWVGhlIGNsYWltIGlzIHZlcmlmaWVkLpRoH05oIIwgMjAyNi0xMC0wMVQwOToxNDowMC4xMjM0NTYrMDA6MDCUaCJOaCOMAmVulHVoJX2UaCePlChoEGgOaBRoGGggaBJoFmgjaCJoHWgaaBtoH5BoKU51YmgKKYGUfZQoaAV9lChoDowIN2M4MzI0N2OUaBCMEExpYnJhcnkgY2xhaW0gMi6UaBKMB1NjaWVuY2WUaBRdlGgWjARUcnVllGgYjANsb3eUaBpLCmgbjC5UaGUgRWFydGggaXMgYXBwcm94aW1hdGVseSBzcGhlcmljYWwgaW4gc2hhcGUulGgdjBZUaGUgY2xhaW0gaXMgdmVyaWZpZWQulGgfTmggjCAyMDI2LTEwLTAxVDA5OjIxOjAwLjEyMzQ1NiswMDowMJRoIk5oI4wCZW6UdWglfZRoJ4+UKGgQaA5oFGgYaCBoEmgWaCNoImgdaBpoG2gfkGgpTnViZYwFdG90YWyUSwOMBHBhZ2WUSwGMCXBhZ2Vfc2l6ZZRLFHVoJX2UaCePlChoSWhKaEhoB5BoKU51Yi4=", + "account__library_no_match.json": "gASVuQAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwLTGlicmFyeUxpc3SUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwFaXRlbXOUXZSMBXRvdGFslEsAjARwYWdllEsBjAlwYWdlX3NpemWUSxR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgKaAtoCWgHkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViLg==", + "account__library_page_past_end.json": "gASVuQAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwLTGlicmFyeUxpc3SUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwFaXRlbXOUXZSMBXRvdGFslEsBjARwYWdllEsCjAlwYWdlX3NpemWUSxR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgKaAtoCWgHkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViLg==", + "account__library_paginated_second_page.json": "gASVTAMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwLTGlicmFyeUxpc3SUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwFaXRlbXOUXZQoaACMC0xpYnJhcnlJdGVtlJOUKYGUfZQoaAV9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBBQYWdlZCBjbGFpbSAwMjAulIwGZG9tYWlulIwAlIwIZW50aXRpZXOUXZSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMA2xvd5SMCmxlbnpfc2NvcmWUSwqMC2tleV9maW5kaW5nlIwuVGhlIEVhcnRoIGlzIGFwcHJveGltYXRlbHkgc3BoZXJpY2FsIGluIHNoYXBlLpSMEWV4ZWN1dGl2ZV9zdW1tYXJ5lIwWVGhlIGNsYWltIGlzIHZlcmlmaWVkLpSMEXN1Z2dlc3RlZF9yZXdyaXRllE6MCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoEGgOaBRoGGggaBJoFmgjaCJoHWgaaBtoH5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmgKKYGUfZQoaAV9lChoDowINGQ0NGRmYWaUaBCMEFBhZ2VkIGNsYWltIDAyMS6UaBJoE2gUXZRoFowEVHJ1ZZRoGIwDbG93lGgaSwpoG4wuVGhlIEVhcnRoIGlzIGFwcHJveGltYXRlbHkgc3BoZXJpY2FsIGluIHNoYXBlLpRoHYwWVGhlIGNsYWltIGlzIHZlcmlmaWVkLpRoH05oIIwgMjAyNi0xMC0wMVQwOToxNDowMC4xMjM0NTYrMDA6MDCUaCJOaCOMAmVulHVoJX2UaCePlChoEGgOaBRoGGggaBJoFmgjaCJoHWgaaBtoH5BoKU51YmWMBXRvdGFslEsWjARwYWdllEsCjAlwYWdlX3NpemWUSxR1aCV9lGgnj5QoaDloOmg4aAeQaClOdWIu", + "account__me_usage_extra_credits.json": "gASVoAMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwFVXNhZ2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwEcGxhbpSMBGZyZWWUjApwbGFuX2xhYmVslIwERnJlZZSMD3F1b3RhX3Jlc2V0c19hdJSMGTIwMjYtMTAtMDFUMTQ6MDc6MDArMDA6MDCUjAdjcmVkaXRzlGgAjAxVc2FnZUNyZWRpdHOUk5QpgZR9lChoBX2UKIwFdG90YWyUTV4BjAR1c2VklEsAjAlyZW1haW5pbmeUTV4BjAVleHRyYZRL+owFYm9udXOUS/qMCXJlc2V0c19hdJSMGTIwMjYtMTAtMDFUMTQ6MDc6MDArMDA6MDCUdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoFGgYaBNoFWgWaBeQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMBWNvc3RzlH2UKIwGdmVyaWZ5lEsKjAZhc3Nlc3OUSwGMA2Fza5RLAYwIY2l0YXRpb26USwGMB2V4dHJhY3SUSwB1jAxjb3N0X29wdGlvbnOUfZRoIX2UjAVkZXB0aJR9lCiMCHN0YW5kYXJklEsKjANsb3eUSwV1c3OMBnZlcmlmeZRoAIwNVXNhZ2VDYXBhY2l0eZSTlCmBlH2UKGgFfZQojApxdW90YV91c2VklEsAjAtxdW90YV90b3RhbJRLI4wPcXVvdGFfcmVtYWluaW5nlEsjaBdLGWgNSxloFUsjdWgafZRoHI+UKGgNaDNoNGgVaDVoF5BoHk51YowDYXNrlGgvKYGUfZQoaAV9lChoM0sAaDRNXgFoNU1eAWgXS/poDUv6aBVNXgF1aBp9lGgcj5QoaA1oM2g0aBVoNWgXkGgeTnVijAZhc3Nlc3OUaC8pgZR9lChoBX2UKGgzSwBoNE1eAWg1TV4BaBdL+mgNS/poFU1eAXVoGn2UaByPlChoDWgzaDRoFWg1aBeQaB5OdWKMB2V4dHJhY3SUaACMDFVzYWdlRXh0cmFjdJSTlCmBlH2UKGgFfZQojAtjYWxsc190b2RheZRLAIwLZGFpbHlfbGltaXSUTegDjAl1bmxpbWl0ZWSUiXVoGn2UaByPlChoS2hMaEqQaB5OdWKMEmhhc193ZWJob29rX3NlY3JldJSJdWgafZRoHI+UKGgtaDhoDWg+aAdoC2gmaE9oH2hEaAmQaB5OdWIu", + "account__me_usage_extra_only.json": "gASVmAMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwFVXNhZ2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwEcGxhbpSMBGZyZWWUjApwbGFuX2xhYmVslIwERnJlZZSMD3F1b3RhX3Jlc2V0c19hdJSMGTIwMjYtMTAtMDFUMTQ6MDc6MDArMDA6MDCUjAdjcmVkaXRzlGgAjAxVc2FnZUNyZWRpdHOUk5QpgZR9lChoBX2UKIwFdG90YWyUS4mMBHVzZWSUS2SMCXJlbWFpbmluZ5RLJYwFZXh0cmGUSyWMBWJvbnVzlEsljAlyZXNldHNfYXSUjBkyMDI2LTEwLTAxVDE0OjA3OjAwKzAwOjAwlHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBRoGGgTaBVoFmgXkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAVjb3N0c5R9lCiMBnZlcmlmeZRLCowGYXNzZXNzlEsBjANhc2uUSwGMCGNpdGF0aW9ulEsBjAdleHRyYWN0lEsAdYwMY29zdF9vcHRpb25zlH2UaCF9lIwFZGVwdGiUfZQojAhzdGFuZGFyZJRLCowDbG93lEsFdXNzjAZ2ZXJpZnmUaACMDVVzYWdlQ2FwYWNpdHmUk5QpgZR9lChoBX2UKIwKcXVvdGFfdXNlZJRLCowLcXVvdGFfdG90YWyUSw2MD3F1b3RhX3JlbWFpbmluZ5RLA2gXSwNoDUsDaBVLA3VoGn2UaByPlChoDWgzaDRoFWg1aBeQaB5OdWKMA2Fza5RoLymBlH2UKGgFfZQoaDNLZGg0S4loNUslaBdLJWgNSyVoFUsldWgafZRoHI+UKGgNaDNoNGgVaDVoF5BoHk51YowGYXNzZXNzlGgvKYGUfZQoaAV9lChoM0tkaDRLiWg1SyVoF0slaA1LJWgVSyV1aBp9lGgcj5QoaA1oM2g0aBVoNWgXkGgeTnVijAdleHRyYWN0lGgAjAxVc2FnZUV4dHJhY3SUk5QpgZR9lChoBX2UKIwLY2FsbHNfdG9kYXmUSwCMC2RhaWx5X2xpbWl0lE3oA4wJdW5saW1pdGVklIl1aBp9lGgcj5QoaEtoTGhKkGgeTnVijBJoYXNfd2ViaG9va19zZWNyZXSUiXVoGn2UaByPlChoLWg4aA1oPmgHaAtoJmhPaB9oRGgJkGgeTnViLg==", + "account__me_usage_extract_calls.json": "gASVmAMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwFVXNhZ2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwEcGxhbpSMBGZyZWWUjApwbGFuX2xhYmVslIwERnJlZZSMD3F1b3RhX3Jlc2V0c19hdJSMGTIwMjYtMTAtMDFUMTQ6MDc6MDArMDA6MDCUjAdjcmVkaXRzlGgAjAxVc2FnZUNyZWRpdHOUk5QpgZR9lChoBX2UKIwFdG90YWyUS2SMBHVzZWSUSwCMCXJlbWFpbmluZ5RLZIwFZXh0cmGUSwCMBWJvbnVzlEsAjAlyZXNldHNfYXSUjBkyMDI2LTEwLTAxVDE0OjA3OjAwKzAwOjAwlHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBRoGGgTaBVoFmgXkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAVjb3N0c5R9lCiMBnZlcmlmeZRLCowGYXNzZXNzlEsBjANhc2uUSwGMCGNpdGF0aW9ulEsBjAdleHRyYWN0lEsAdYwMY29zdF9vcHRpb25zlH2UaCF9lIwFZGVwdGiUfZQojAhzdGFuZGFyZJRLCowDbG93lEsFdXNzjAZ2ZXJpZnmUaACMDVVzYWdlQ2FwYWNpdHmUk5QpgZR9lChoBX2UKIwKcXVvdGFfdXNlZJRLAIwLcXVvdGFfdG90YWyUSwqMD3F1b3RhX3JlbWFpbmluZ5RLCmgXSwBoDUsAaBVLCnVoGn2UaByPlChoDWgzaDRoFWg1aBeQaB5OdWKMA2Fza5RoLymBlH2UKGgFfZQoaDNLAGg0S2RoNUtkaBdLAGgNSwBoFUtkdWgafZRoHI+UKGgNaDNoNGgVaDVoF5BoHk51YowGYXNzZXNzlGgvKYGUfZQoaAV9lChoM0sAaDRLZGg1S2RoF0sAaA1LAGgVS2R1aBp9lGgcj5QoaA1oM2g0aBVoNWgXkGgeTnVijAdleHRyYWN0lGgAjAxVc2FnZUV4dHJhY3SUk5QpgZR9lChoBX2UKIwLY2FsbHNfdG9kYXmUSweMC2RhaWx5X2xpbWl0lE3oA4wJdW5saW1pdGVklIl1aBp9lGgcj5QoaEtoTGhKkGgeTnVijBJoYXNfd2ViaG9va19zZWNyZXSUiXVoGn2UaByPlChoLWg4aA1oPmgHaAtoJmhPaB9oRGgJkGgeTnViLg==", + "account__me_usage_free.json": "gASVmAMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwFVXNhZ2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwEcGxhbpSMBGZyZWWUjApwbGFuX2xhYmVslIwERnJlZZSMD3F1b3RhX3Jlc2V0c19hdJSMGTIwMjYtMTAtMDFUMTQ6MDc6MDArMDA6MDCUjAdjcmVkaXRzlGgAjAxVc2FnZUNyZWRpdHOUk5QpgZR9lChoBX2UKIwFdG90YWyUS2SMBHVzZWSUSwCMCXJlbWFpbmluZ5RLZIwFZXh0cmGUSwCMBWJvbnVzlEsAjAlyZXNldHNfYXSUjBkyMDI2LTEwLTAxVDE0OjA3OjAwKzAwOjAwlHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBRoGGgTaBVoFmgXkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAVjb3N0c5R9lCiMBnZlcmlmeZRLCowGYXNzZXNzlEsBjANhc2uUSwGMCGNpdGF0aW9ulEsBjAdleHRyYWN0lEsAdYwMY29zdF9vcHRpb25zlH2UaCF9lIwFZGVwdGiUfZQojAhzdGFuZGFyZJRLCowDbG93lEsFdXNzjAZ2ZXJpZnmUaACMDVVzYWdlQ2FwYWNpdHmUk5QpgZR9lChoBX2UKIwKcXVvdGFfdXNlZJRLAIwLcXVvdGFfdG90YWyUSwqMD3F1b3RhX3JlbWFpbmluZ5RLCmgXSwBoDUsAaBVLCnVoGn2UaByPlChoDWgzaDRoFWg1aBeQaB5OdWKMA2Fza5RoLymBlH2UKGgFfZQoaDNLAGg0S2RoNUtkaBdLAGgNSwBoFUtkdWgafZRoHI+UKGgNaDNoNGgVaDVoF5BoHk51YowGYXNzZXNzlGgvKYGUfZQoaAV9lChoM0sAaDRLZGg1S2RoF0sAaA1LAGgVS2R1aBp9lGgcj5QoaA1oM2g0aBVoNWgXkGgeTnVijAdleHRyYWN0lGgAjAxVc2FnZUV4dHJhY3SUk5QpgZR9lChoBX2UKIwLY2FsbHNfdG9kYXmUSwCMC2RhaWx5X2xpbWl0lE3oA4wJdW5saW1pdGVklIl1aBp9lGgcj5QoaEtoTGhKkGgeTnVijBJoYXNfd2ViaG9va19zZWNyZXSUiXVoGn2UaByPlChoLWg4aA1oPmgHaAtoJmhPaB9oRGgJkGgeTnViLg==", + "account__me_usage_free_partly_spent.json": "gASVmAMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwFVXNhZ2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwEcGxhbpSMBGZyZWWUjApwbGFuX2xhYmVslIwERnJlZZSMD3F1b3RhX3Jlc2V0c19hdJSMGTIwMjYtMTAtMDFUMTQ6MDc6MDArMDA6MDCUjAdjcmVkaXRzlGgAjAxVc2FnZUNyZWRpdHOUk5QpgZR9lChoBX2UKIwFdG90YWyUS2SMBHVzZWSUSxGMCXJlbWFpbmluZ5RLU4wFZXh0cmGUSwCMBWJvbnVzlEsAjAlyZXNldHNfYXSUjBkyMDI2LTEwLTAxVDE0OjA3OjAwKzAwOjAwlHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBRoGGgTaBVoFmgXkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAVjb3N0c5R9lCiMBnZlcmlmeZRLCowGYXNzZXNzlEsBjANhc2uUSwGMCGNpdGF0aW9ulEsBjAdleHRyYWN0lEsAdYwMY29zdF9vcHRpb25zlH2UaCF9lIwFZGVwdGiUfZQojAhzdGFuZGFyZJRLCowDbG93lEsFdXNzjAZ2ZXJpZnmUaACMDVVzYWdlQ2FwYWNpdHmUk5QpgZR9lChoBX2UKIwKcXVvdGFfdXNlZJRLAowLcXVvdGFfdG90YWyUSwqMD3F1b3RhX3JlbWFpbmluZ5RLCGgXSwBoDUsAaBVLCHVoGn2UaByPlChoDWgzaDRoFWg1aBeQaB5OdWKMA2Fza5RoLymBlH2UKGgFfZQoaDNLEWg0S2RoNUtTaBdLAGgNSwBoFUtTdWgafZRoHI+UKGgNaDNoNGgVaDVoF5BoHk51YowGYXNzZXNzlGgvKYGUfZQoaAV9lChoM0sRaDRLZGg1S1NoF0sAaA1LAGgVS1N1aBp9lGgcj5QoaA1oM2g0aBVoNWgXkGgeTnVijAdleHRyYWN0lGgAjAxVc2FnZUV4dHJhY3SUk5QpgZR9lChoBX2UKIwLY2FsbHNfdG9kYXmUSwCMC2RhaWx5X2xpbWl0lE3oA4wJdW5saW1pdGVklIl1aBp9lGgcj5QoaEtoTGhKkGgeTnVijBJoYXNfd2ViaG9va19zZWNyZXSUiXVoGn2UaByPlChoLWg4aA1oPmgHaAtoJmhPaB9oRGgJkGgeTnViLg==", + "account__me_usage_oauth.json": "gASVmAMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwFVXNhZ2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwEcGxhbpSMBGZyZWWUjApwbGFuX2xhYmVslIwERnJlZZSMD3F1b3RhX3Jlc2V0c19hdJSMGTIwMjYtMTAtMDFUMTQ6MDc6MDArMDA6MDCUjAdjcmVkaXRzlGgAjAxVc2FnZUNyZWRpdHOUk5QpgZR9lChoBX2UKIwFdG90YWyUS2SMBHVzZWSUSwCMCXJlbWFpbmluZ5RLZIwFZXh0cmGUSwCMBWJvbnVzlEsAjAlyZXNldHNfYXSUjBkyMDI2LTEwLTAxVDE0OjA3OjAwKzAwOjAwlHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBRoGGgTaBVoFmgXkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAVjb3N0c5R9lCiMBnZlcmlmeZRLCowGYXNzZXNzlEsBjANhc2uUSwGMCGNpdGF0aW9ulEsBjAdleHRyYWN0lEsAdYwMY29zdF9vcHRpb25zlH2UaCF9lIwFZGVwdGiUfZQojAhzdGFuZGFyZJRLCowDbG93lEsFdXNzjAZ2ZXJpZnmUaACMDVVzYWdlQ2FwYWNpdHmUk5QpgZR9lChoBX2UKIwKcXVvdGFfdXNlZJRLAIwLcXVvdGFfdG90YWyUSwqMD3F1b3RhX3JlbWFpbmluZ5RLCmgXSwBoDUsAaBVLCnVoGn2UaByPlChoDWgzaDRoFWg1aBeQaB5OdWKMA2Fza5RoLymBlH2UKGgFfZQoaDNLAGg0S2RoNUtkaBdLAGgNSwBoFUtkdWgafZRoHI+UKGgNaDNoNGgVaDVoF5BoHk51YowGYXNzZXNzlGgvKYGUfZQoaAV9lChoM0sAaDRLZGg1S2RoF0sAaA1LAGgVS2R1aBp9lGgcj5QoaA1oM2g0aBVoNWgXkGgeTnVijAdleHRyYWN0lGgAjAxVc2FnZUV4dHJhY3SUk5QpgZR9lChoBX2UKIwLY2FsbHNfdG9kYXmUSwCMC2RhaWx5X2xpbWl0lE3oA4wJdW5saW1pdGVklIl1aBp9lGgcj5QoaEtoTGhKkGgeTnVijBJoYXNfd2ViaG9va19zZWNyZXSUiXVoGn2UaByPlChoLWg4aA1oPmgHaAtoJmhPaB9oRGgJkGgeTnViLg==", + "account__me_usage_plus.json": "gASVrgMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwFVXNhZ2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwEcGxhbpSMBHBsdXOUjApwbGFuX2xhYmVslIwEUGx1c5SMD3F1b3RhX3Jlc2V0c19hdJSMIDIwMjYtMTAtMDFUMTQ6MDc6MDAuMTIzNDU2KzAwOjAwlIwHY3JlZGl0c5RoAIwMVXNhZ2VDcmVkaXRzlJOUKYGUfZQoaAV9lCiMBXRvdGFslE30AYwEdXNlZJRLAIwJcmVtYWluaW5nlE30AYwFZXh0cmGUSwCMBWJvbnVzlEsAjAlyZXNldHNfYXSUjCAyMDI2LTEwLTAxVDE0OjA3OjAwLjEyMzQ1NiswMDowMJR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgUaBhoE2gVaBZoF5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowFY29zdHOUfZQojAZ2ZXJpZnmUSwqMBmFzc2Vzc5RLAYwDYXNrlEsBjAhjaXRhdGlvbpRLAYwHZXh0cmFjdJRLAHWMDGNvc3Rfb3B0aW9uc5R9lGghfZSMBWRlcHRolH2UKIwIc3RhbmRhcmSUSwqMA2xvd5RLBXVzc4wGdmVyaWZ5lGgAjA1Vc2FnZUNhcGFjaXR5lJOUKYGUfZQoaAV9lCiMCnF1b3RhX3VzZWSUSwCMC3F1b3RhX3RvdGFslEsyjA9xdW90YV9yZW1haW5pbmeUSzJoF0sAaA1LAGgVSzJ1aBp9lGgcj5QoaA1oM2g0aBVoNWgXkGgeTnVijANhc2uUaC8pgZR9lChoBX2UKGgzSwBoNE30AWg1TfQBaBdLAGgNSwBoFU30AXVoGn2UaByPlChoDWgzaDRoFWg1aBeQaB5OdWKMBmFzc2Vzc5RoLymBlH2UKGgFfZQoaDNLAGg0TfQBaDVN9AFoF0sAaA1LAGgVTfQBdWgafZRoHI+UKGgNaDNoNGgVaDVoF5BoHk51YowHZXh0cmFjdJRoAIwMVXNhZ2VFeHRyYWN0lJOUKYGUfZQoaAV9lCiMC2NhbGxzX3RvZGF5lEsAjAtkYWlseV9saW1pdJRN6AOMCXVubGltaXRlZJSJdWgafZRoHI+UKGhLaExoSpBoHk51YowSaGFzX3dlYmhvb2tfc2VjcmV0lIl1aBp9lGgcj5QoaC1oOGgNaD5oB2gLaCZoT2gfaERoCZBoHk51Yi4=", + "account__me_usage_pro.json": "gASVrwMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwFVXNhZ2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwEcGxhbpSMA3Byb5SMCnBsYW5fbGFiZWyUjANQcm+UjA9xdW90YV9yZXNldHNfYXSUjCAyMDI2LTEwLTAxVDE0OjA3OjAwLjEyMzQ1NiswMDowMJSMB2NyZWRpdHOUaACMDFVzYWdlQ3JlZGl0c5STlCmBlH2UKGgFfZQojAV0b3RhbJRNiBOMBHVzZWSUSwCMCXJlbWFpbmluZ5RNiBOMBWV4dHJhlEsAjAVib251c5RLAIwJcmVzZXRzX2F0lIwgMjAyNi0xMC0wMVQxNDowNzowMC4xMjM0NTYrMDA6MDCUdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoFGgYaBNoFWgWaBeQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMBWNvc3RzlH2UKIwGdmVyaWZ5lEsKjAZhc3Nlc3OUSwGMA2Fza5RLAYwIY2l0YXRpb26USwGMB2V4dHJhY3SUSwB1jAxjb3N0X29wdGlvbnOUfZRoIX2UjAVkZXB0aJR9lCiMCHN0YW5kYXJklEsKjANsb3eUSwV1c3OMBnZlcmlmeZRoAIwNVXNhZ2VDYXBhY2l0eZSTlCmBlH2UKGgFfZQojApxdW90YV91c2VklEsAjAtxdW90YV90b3RhbJRN9AGMD3F1b3RhX3JlbWFpbmluZ5RN9AFoF0sAaA1LAGgVTfQBdWgafZRoHI+UKGgNaDNoNGgVaDVoF5BoHk51YowDYXNrlGgvKYGUfZQoaAV9lChoM0sAaDRNiBNoNU2IE2gXSwBoDUsAaBVNiBN1aBp9lGgcj5QoaA1oM2g0aBVoNWgXkGgeTnVijAZhc3Nlc3OUaC8pgZR9lChoBX2UKGgzSwBoNE2IE2g1TYgTaBdLAGgNSwBoFU2IE3VoGn2UaByPlChoDWgzaDRoFWg1aBeQaB5OdWKMB2V4dHJhY3SUaACMDFVzYWdlRXh0cmFjdJSTlCmBlH2UKGgFfZQojAtjYWxsc190b2RheZRLAIwLZGFpbHlfbGltaXSUTegDjAl1bmxpbWl0ZWSUiXVoGn2UaByPlChoS2hMaEqQaB5OdWKMEmhhc193ZWJob29rX3NlY3JldJSJdWgafZRoHI+UKGgtaDhoDWg+aAdoC2gmaE9oH2hEaAmQaB5OdWIu", + "account__me_usage_pro_extra.json": "gASVtQMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwFVXNhZ2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwEcGxhbpSMA3Byb5SMCnBsYW5fbGFiZWyUjANQcm+UjA9xdW90YV9yZXNldHNfYXSUjCAyMDI2LTEwLTAxVDE0OjA3OjAwLjEyMzQ1NiswMDowMJSMB2NyZWRpdHOUaACMDFVzYWdlQ3JlZGl0c5STlCmBlH2UKGgFfZQojAV0b3RhbJRNcBeMBHVzZWSUSwCMCXJlbWFpbmluZ5RNcBeMBWV4dHJhlE3oA4wFYm9udXOUTegDjAlyZXNldHNfYXSUjCAyMDI2LTEwLTAxVDE0OjA3OjAwLjEyMzQ1NiswMDowMJR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgUaBhoE2gVaBZoF5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowFY29zdHOUfZQojAZ2ZXJpZnmUSwqMBmFzc2Vzc5RLAYwDYXNrlEsBjAhjaXRhdGlvbpRLAYwHZXh0cmFjdJRLAHWMDGNvc3Rfb3B0aW9uc5R9lGghfZSMBWRlcHRolH2UKIwIc3RhbmRhcmSUSwqMA2xvd5RLBXVzc4wGdmVyaWZ5lGgAjA1Vc2FnZUNhcGFjaXR5lJOUKYGUfZQoaAV9lCiMCnF1b3RhX3VzZWSUSwCMC3F1b3RhX3RvdGFslE1YAowPcXVvdGFfcmVtYWluaW5nlE1YAmgXS2RoDUtkaBVNWAJ1aBp9lGgcj5QoaA1oM2g0aBVoNWgXkGgeTnVijANhc2uUaC8pgZR9lChoBX2UKGgzSwBoNE1wF2g1TXAXaBdN6ANoDU3oA2gVTXAXdWgafZRoHI+UKGgNaDNoNGgVaDVoF5BoHk51YowGYXNzZXNzlGgvKYGUfZQoaAV9lChoM0sAaDRNcBdoNU1wF2gXTegDaA1N6ANoFU1wF3VoGn2UaByPlChoDWgzaDRoFWg1aBeQaB5OdWKMB2V4dHJhY3SUaACMDFVzYWdlRXh0cmFjdJSTlCmBlH2UKGgFfZQojAtjYWxsc190b2RheZRLAIwLZGFpbHlfbGltaXSUTegDjAl1bmxpbWl0ZWSUiXVoGn2UaByPlChoS2hMaEqQaB5OdWKMEmhhc193ZWJob29rX3NlY3JldJSJdWgafZRoHI+UKGgtaDhoDWg+aAdoC2gmaE9oH2hEaAmQaB5OdWIu", + "account__me_usage_stale_quota_row.json": "gASVmAMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwFVXNhZ2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwEcGxhbpSMBGZyZWWUjApwbGFuX2xhYmVslIwERnJlZZSMD3F1b3RhX3Jlc2V0c19hdJSMGTIwMjYtMTAtMDFUMTQ6MDc6MDArMDA6MDCUjAdjcmVkaXRzlGgAjAxVc2FnZUNyZWRpdHOUk5QpgZR9lChoBX2UKIwFdG90YWyUS2SMBHVzZWSUSwCMCXJlbWFpbmluZ5RLZIwFZXh0cmGUSwCMBWJvbnVzlEsAjAlyZXNldHNfYXSUjBkyMDI2LTEwLTAxVDE0OjA3OjAwKzAwOjAwlHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBRoGGgTaBVoFmgXkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAVjb3N0c5R9lCiMBnZlcmlmeZRLCowGYXNzZXNzlEsBjANhc2uUSwGMCGNpdGF0aW9ulEsBjAdleHRyYWN0lEsAdYwMY29zdF9vcHRpb25zlH2UaCF9lIwFZGVwdGiUfZQojAhzdGFuZGFyZJRLCowDbG93lEsFdXNzjAZ2ZXJpZnmUaACMDVVzYWdlQ2FwYWNpdHmUk5QpgZR9lChoBX2UKIwKcXVvdGFfdXNlZJRLAIwLcXVvdGFfdG90YWyUSwqMD3F1b3RhX3JlbWFpbmluZ5RLCmgXSwBoDUsAaBVLCnVoGn2UaByPlChoDWgzaDRoFWg1aBeQaB5OdWKMA2Fza5RoLymBlH2UKGgFfZQoaDNLAGg0S2RoNUtkaBdLAGgNSwBoFUtkdWgafZRoHI+UKGgNaDNoNGgVaDVoF5BoHk51YowGYXNzZXNzlGgvKYGUfZQoaAV9lChoM0sAaDRLZGg1S2RoF0sAaA1LAGgVS2R1aBp9lGgcj5QoaA1oM2g0aBVoNWgXkGgeTnVijAdleHRyYWN0lGgAjAxVc2FnZUV4dHJhY3SUk5QpgZR9lChoBX2UKIwLY2FsbHNfdG9kYXmUSwCMC2RhaWx5X2xpbWl0lE3oA4wJdW5saW1pdGVklIl1aBp9lGgcj5QoaEtoTGhKkGgeTnVijBJoYXNfd2ViaG9va19zZWNyZXSUiXVoGn2UaByPlChoLWg4aA1oPmgHaAtoJmhPaB9oRGgJkGgeTnViLg==", + "assess__deep_tier_hit.json": "gASVHwIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UaACMC0Fzc2Vzc0NsYWltlJOUKYGUfZQoaAV9lCiMBWNsYWltlIwUV2F0ZXIgYm9pbHMgYXQgMTAwQy6UjAhsYW5ndWFnZZSMAmVulIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwEaGlnaJSMEHZlcmlmaWNhdGlvbl91cmyUjC1odHRwczovL2xlbnouaW8vYXBpL3YxL3ZlcmlmaWNhdGlvbnMvZjM0MzZmNTCUjAlyYXRpb25hbGWUjBZUaGUgY2xhaW0gaXMgdmVyaWZpZWQulIwHZGlzc2VudJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAplcnJvcl9jb2RllE6MEGNhbmRpZGF0ZV9jbGFpbXOUXZSMEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE51jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgOaCFoGmgdaBZoEGgUaB9oEmgYaBxoG5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMBWVycm9ylE5oHIwAlGgdXZSMC21vcmVfY2xhaW1zlF2UdWgifZRoJI+UKGgHaCpoJ5BoJk51Yi4=", + "assess__idempotency_first.json": "gASV3QEAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UaACMC0Fzc2Vzc0NsYWltlJOUKYGUfZQoaAV9lCiMBWNsYWltlIwZVGhlIEVhcnRoIG9yYml0cyB0aGUgU3VuLpSMCGxhbmd1YWdllIwCZW6UjAd2ZXJkaWN0lIwEVHJ1ZZSMCmNvbmZpZGVuY2WUjARoaWdolIwQdmVyaWZpY2F0aW9uX3VybJROjAlyYXRpb25hbGWUTowHZGlzc2VudJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAplcnJvcl9jb2RllE6MEGNhbmRpZGF0ZV9jbGFpbXOUXZSMEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE51jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgOaB9oGGgbaBZoEGgUaB1oEmgXaBpoGZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMBWVycm9ylE5oGowAlGgbXZSMC21vcmVfY2xhaW1zlF2UdWggfZRoIo+UKGgHaChoJZBoJE51Yi4=", + "assess__idempotency_replay.json": "gASV3QEAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UaACMC0Fzc2Vzc0NsYWltlJOUKYGUfZQoaAV9lCiMBWNsYWltlIwZVGhlIEVhcnRoIG9yYml0cyB0aGUgU3VuLpSMCGxhbmd1YWdllIwCZW6UjAd2ZXJkaWN0lIwEVHJ1ZZSMCmNvbmZpZGVuY2WUjARoaWdolIwQdmVyaWZpY2F0aW9uX3VybJROjAlyYXRpb25hbGWUTowHZGlzc2VudJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAplcnJvcl9jb2RllE6MEGNhbmRpZGF0ZV9jbGFpbXOUXZSMEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE51jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgOaB9oGGgbaBZoEGgUaB1oEmgXaBpoGZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMBWVycm9ylE5oGowAlGgbXZSMC21vcmVfY2xhaW1zlF2UdWggfZRoIo+UKGgHaChoJZBoJE51Yi4=", + "assess__list_all_error_rows.json": "gASVJQMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UKGgAjAtBc3Nlc3NDbGFpbZSTlCmBlH2UKGgFfZQojAVjbGFpbZSMAmhplIwIbGFuZ3VhZ2WUjAJlbpSMB3ZlcmRpY3SUjAVFcnJvcpSMCmNvbmZpZGVuY2WUjANsb3eUjBB2ZXJpZmljYXRpb25fdXJslE6MCXJhdGlvbmFsZZROjAdkaXNzZW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE6MCmVycm9yX2NvZGWUjAhub19jbGFpbZSMEGNhbmRpZGF0ZV9jbGFpbXOUXZSMEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lIxqVGhlIGlucHV0IGlzIGEgZ3JlZXRpbmcuIFNlbmQgb25lIGZhY3R1YWwgY2xhaW0sIG9yIHJ1biB0aGUgdGV4dCB0aHJvdWdoIC9leHRyYWN0IHRvIGVudW1lcmF0ZSBpdHMgY2xhaW1zLpR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgOaCBoGGgcaBZoEGgUaB5oEmgXaBpoGZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmgKKYGUfZQoaAV9lChoDowFaGVsbG+UaBCMAmVulGgSjAVFcnJvcpRoFIwDbG93lGgWTmgXTmgYTmgZTmgajAhub19jbGFpbZRoHF2UaB5dlGggjGpUaGUgaW5wdXQgaXMgYSBncmVldGluZy4gU2VuZCBvbmUgZmFjdHVhbCBjbGFpbSwgb3IgcnVuIHRoZSB0ZXh0IHRocm91Z2ggL2V4dHJhY3QgdG8gZW51bWVyYXRlIGl0cyBjbGFpbXMulHVoIn2UaCSPlChoDmggaBhoHGgWaBBoFGgeaBJoF2gaaBmQaCZOdWJljAVlcnJvcpROaBqMAJRoHF2UjAttb3JlX2NsYWltc5RdlHVoIn2UaCSPlChoB2g3aDSQaCZOdWIu", + "assess__list_compound_item.json": "gASV2wIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UKGgAjAtBc3Nlc3NDbGFpbZSTlCmBlH2UKGgFfZQojAVjbGFpbZSMDlByaW1hcnkgY2xhaW0ulIwIbGFuZ3VhZ2WUjAJlbpSMB3ZlcmRpY3SUjAxNb3N0bHkgRmFsc2WUjApjb25maWRlbmNllIwEaGlnaJSMEHZlcmlmaWNhdGlvbl91cmyUTowJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowRc3VnZ2VzdGVkX3Jld3JpdGWUTowKZXJyb3JfY29kZZROjBBjYW5kaWRhdGVfY2xhaW1zlF2UjBFpZGVudGlmaWVkX2NsYWltc5RdlCiMDVNlY29uZCBjbGFpbS6UjAxUaGlyZCBjbGFpbS6UZYwEaGludJSMWkFzc2Vzc2VkIHRoZSBtYWluIGNsYWltIG9ubHkuIFNlbmQgaWRlbnRpZmllZF9jbGFpbXMgYXMgdGhlaXIgb3duIGl0ZW1zIHRvIGNoZWNrIHRoZSByZXN0LpR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgOaCFoGGgbaBZoEGgUaB1oEmgXaBpoGZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmgKKYGUfZQoaAV9lChoDowOQSBwbGFpbiBjbGFpbS6UaBCMAmVulGgSjAxNb3N0bHkgRmFsc2WUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoIU51aCN9lGglj5QoaA5oIWgYaBtoFmgQaBRoHWgSaBdoGmgZkGgnTnViZYwFZXJyb3KUTmgajACUaBtdlIwLbW9yZV9jbGFpbXOUXZR1aCN9lGglj5QoaAdoNmgzkGgnTnViLg==", + "assess__list_mixed_rows.json": "gASVxAQAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UKGgAjAtBc3Nlc3NDbGFpbZSTlCmBlH2UKGgFfZQojAVjbGFpbZSMIldhdGVyIGJvaWxzIGF0IDEwMCBDIGF0IHNlYSBsZXZlbC6UjAhsYW5ndWFnZZSMAmVulIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwEaGlnaJSMEHZlcmlmaWNhdGlvbl91cmyUTowJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowRc3VnZ2VzdGVkX3Jld3JpdGWUTowKZXJyb3JfY29kZZROjBBjYW5kaWRhdGVfY2xhaW1zlF2UjBFpZGVudGlmaWVkX2NsYWltc5RdlIwEaGludJROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoDmgfaBhoG2gWaBBoFGgdaBJoF2gaaBmQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJoCimBlH2UKGgFfZQoaA6MC2hlbGxvIHRoZXJllGgQjAJlbpRoEowFRXJyb3KUaBSMA2xvd5RoFk5oF05oGE5oGU5oGowIbm9fY2xhaW2UaBtdlGgdXZRoH4xqVGhlIGlucHV0IGlzIGEgZ3JlZXRpbmcuIFNlbmQgb25lIGZhY3R1YWwgY2xhaW0sIG9yIHJ1biB0aGUgdGV4dCB0aHJvdWdoIC9leHRyYWN0IHRvIGVudW1lcmF0ZSBpdHMgY2xhaW1zLpR1aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjA52ZW5kb3IgaXMgZG93bpRoEIwCZW6UaBKMBUVycm9ylGgUjANsb3eUaBZOaBdOaBhOaBlOaBqMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGgbXZRoHV2UaB+MTkEgbW9kZWwgcHJvdmlkZXIgd2FzIHVuYXZhaWxhYmxlIGZvciB0aGlzIGl0ZW0uIFJldHJ5IGl0OyBub3RoaW5nIHdhcyBjaGFyZ2VkLpR1aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjAxjYW5ub3QgZnJhbWWUaBCMAmVulGgSjAVFcnJvcpRoFIwDbG93lGgWTmgXTmgYTmgZTmgajA5mcmFtaW5nX2ZhaWxlZJRoG12UaB1dlGgfjINUaGlzIGl0ZW0gY291bGQgbm90IGJlIHByb2Nlc3NlZDsgcmV0cnlpbmcgaXQgYXMtaXMgd2lsbCBub3QgaGVscC4gU2VuZCBpdCByZXBocmFzZWQgYXMgb25lIGZhY3R1YWwgc3RhdGVtZW50OyBub3RoaW5nIHdhcyBjaGFyZ2VkLpR1aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViZYwFZXJyb3KUTmgajACUaBtdlIwLbW9yZV9jbGFpbXOUXZR1aCB9lGgij5QoaAdoT2hMkGgkTnViLg==", + "assess__memo_hit.json": "gASVBgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UaACMC0Fzc2Vzc0NsYWltlJOUKYGUfZQoaAV9lCiMBWNsYWltlIwgVGhlIERhbnViZSBmbG93cyB0aHJvdWdoIFZpZW5uYS6UjAhsYW5ndWFnZZSMAmVulIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwEaGlnaJSMEHZlcmlmaWNhdGlvbl91cmyUTowJcmF0aW9uYWxllIwgVGhlIHJpdmVyIHJ1bnMgdGhyb3VnaCB0aGUgY2l0eS6UjAdkaXNzZW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE6MCmVycm9yX2NvZGWUTowQY2FuZGlkYXRlX2NsYWltc5RdlIwRaWRlbnRpZmllZF9jbGFpbXOUXZSMBGhpbnSUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaA5oIGgZaBxoFmgQaBRoHmgSaBdoG2gakIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViYYwFZXJyb3KUTmgbjACUaBxdlIwLbW9yZV9jbGFpbXOUXZR1aCF9lGgjj5QoaAdoKWgmkGglTnViLg==", + "assess__replay_later_200.json": "gASV3QEAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UaACMC0Fzc2Vzc0NsYWltlJOUKYGUfZQoaAV9lCiMBWNsYWltlIwZVGhlIEVhcnRoIG9yYml0cyB0aGUgU3VuLpSMCGxhbmd1YWdllIwCZW6UjAd2ZXJkaWN0lIwEVHJ1ZZSMCmNvbmZpZGVuY2WUjARoaWdolIwQdmVyaWZpY2F0aW9uX3VybJROjAlyYXRpb25hbGWUTowHZGlzc2VudJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAplcnJvcl9jb2RllE6MEGNhbmRpZGF0ZV9jbGFpbXOUXZSMEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE51jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgOaB9oGGgbaBZoEGgUaB1oEmgXaBpoGZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMBWVycm9ylE5oGowAlGgbXZSMC21vcmVfY2xhaW1zlF2UdWggfZRoIo+UKGgHaChoJZBoJE51Yi4=", + "assess__single_no_claim.json": "gASVAgEAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UjAVlcnJvcpSMHE5vIHZlcmlmaWFibGUgY2xhaW0gZGV0ZWN0ZWSUjAplcnJvcl9jb2RllIwIbm9fY2xhaW2UjBBjYW5kaWRhdGVfY2xhaW1zlF2UjAttb3JlX2NsYWltc5RdlHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaA1oD2gLaAdoCZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51Yi4=", + "assess__single_one_claim.json": "gASViwIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UaACMC0Fzc2Vzc0NsYWltlJOUKYGUfZQoaAV9lCiMBWNsYWltlIwsVGhlIHJlZ2lzdHJ5IHJlcG9ydGVkIDQsMjAwIGZpbGluZ3MgaW4gMjAyNC6UjAhsYW5ndWFnZZSMAmVulIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwEaGlnaJSMEHZlcmlmaWNhdGlvbl91cmyUTowJcmF0aW9uYWxllIxJVGhlIHJlZ2lzdHJ5IGxpc3RzIDQsMjAwIGZpbGluZ3MgZm9yIDIwMjQgYW5kIGhhcyBub3QgcmV2aXNlZCB0aGUgZmlndXJlLpSMB2Rpc3NlbnSUjE5UaGUgcmVnaXN0cnkgZmlndXJlIGlzIHByb3Zpc2lvbmFsLCBzbyB0aGUgMjAyNCB0b3RhbCBjYW5ub3QgeWV0IGJlIGNvbmZpcm1lZC6UjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAplcnJvcl9jb2RllE6MEGNhbmRpZGF0ZV9jbGFpbXOUXZSMEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE51jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgOaCFoGWgdaBZoEGgUaB9oEmgXaBxoG5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMBWVycm9ylE5oHIwAlGgdXZSMC21vcmVfY2xhaW1zlF2UdWgifZRoJI+UKGgHaCpoJ5BoJk51Yi4=", + "assess__single_text_over_wave_more_claims.json": "gASVbgwAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UKGgAjAtBc3Nlc3NDbGFpbZSTlCmBlH2UKGgFfZQojAVjbGFpbZSMHUNsYWltIG51bWJlciAwIGlzIGRvY3VtZW50ZWQulIwIbGFuZ3VhZ2WUjAJlbpSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjBB2ZXJpZmljYXRpb25fdXJslE6MCXJhdGlvbmFsZZROjAdkaXNzZW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE6MCmVycm9yX2NvZGWUTowQY2FuZGlkYXRlX2NsYWltc5RdlIwRaWRlbnRpZmllZF9jbGFpbXOUXZSMBGhpbnSUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViaAopgZR9lChoBX2UKGgOjB1DbGFpbSBudW1iZXIgMSBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB1DbGFpbSBudW1iZXIgMiBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB1DbGFpbSBudW1iZXIgMyBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB1DbGFpbSBudW1iZXIgNCBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB1DbGFpbSBudW1iZXIgNSBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB1DbGFpbSBudW1iZXIgNiBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB1DbGFpbSBudW1iZXIgNyBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB1DbGFpbSBudW1iZXIgOCBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB1DbGFpbSBudW1iZXIgOSBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB5DbGFpbSBudW1iZXIgMTAgaXMgZG9jdW1lbnRlZC6UaBCMAmVulGgSjARUcnVllGgUjARoaWdolGgWTmgXTmgYTmgZTmgaTmgbXZRoHV2UaB9OdWggfZRoIo+UKGgOaB9oGGgbaBZoEGgUaB1oEmgXaBpoGZBoJE51YmgKKYGUfZQoaAV9lChoDoweQ2xhaW0gbnVtYmVyIDExIGlzIGRvY3VtZW50ZWQulGgQjAJlbpRoEowEVHJ1ZZRoFIwEaGlnaJRoFk5oF05oGE5oGU5oGk5oG12UaB1dlGgfTnVoIH2UaCKPlChoDmgfaBhoG2gWaBBoFGgdaBJoF2gaaBmQaCROdWJoCimBlH2UKGgFfZQoaA6MHkNsYWltIG51bWJlciAxMiBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB5DbGFpbSBudW1iZXIgMTMgaXMgZG9jdW1lbnRlZC6UaBCMAmVulGgSjARUcnVllGgUjARoaWdolGgWTmgXTmgYTmgZTmgaTmgbXZRoHV2UaB9OdWggfZRoIo+UKGgOaB9oGGgbaBZoEGgUaB1oEmgXaBpoGZBoJE51YmgKKYGUfZQoaAV9lChoDoweQ2xhaW0gbnVtYmVyIDE0IGlzIGRvY3VtZW50ZWQulGgQjAJlbpRoEowEVHJ1ZZRoFIwEaGlnaJRoFk5oF05oGE5oGU5oGk5oG12UaB1dlGgfTnVoIH2UaCKPlChoDmgfaBhoG2gWaBBoFGgdaBJoF2gaaBmQaCROdWJoCimBlH2UKGgFfZQoaA6MHkNsYWltIG51bWJlciAxNSBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB5DbGFpbSBudW1iZXIgMTYgaXMgZG9jdW1lbnRlZC6UaBCMAmVulGgSjARUcnVllGgUjARoaWdolGgWTmgXTmgYTmgZTmgaTmgbXZRoHV2UaB9OdWggfZRoIo+UKGgOaB9oGGgbaBZoEGgUaB1oEmgXaBpoGZBoJE51YmgKKYGUfZQoaAV9lChoDoweQ2xhaW0gbnVtYmVyIDE3IGlzIGRvY3VtZW50ZWQulGgQjAJlbpRoEowEVHJ1ZZRoFIwEaGlnaJRoFk5oF05oGE5oGU5oGk5oG12UaB1dlGgfTnVoIH2UaCKPlChoDmgfaBhoG2gWaBBoFGgdaBJoF2gaaBmQaCROdWJoCimBlH2UKGgFfZQoaA6MHkNsYWltIG51bWJlciAxOCBpcyBkb2N1bWVudGVkLpRoEIwCZW6UaBKMBFRydWWUaBSMBGhpZ2iUaBZOaBdOaBhOaBlOaBpOaBtdlGgdXZRoH051aCB9lGgij5QoaA5oH2gYaBtoFmgQaBRoHWgSaBdoGmgZkGgkTnViaAopgZR9lChoBX2UKGgOjB5DbGFpbSBudW1iZXIgMTkgaXMgZG9jdW1lbnRlZC6UaBCMAmVulGgSjARUcnVllGgUjARoaWdolGgWTmgXTmgYTmgZTmgaTmgbXZRoHV2UaB9OdWggfZRoIo+UKGgOaB9oGGgbaBZoEGgUaB1oEmgXaBpoGZBoJE51YmWMBWVycm9ylE5oGowAlGgbXZSMC21vcmVfY2xhaW1zlF2UKIweQ2xhaW0gbnVtYmVyIDIwIGlzIGRvY3VtZW50ZWQulIweQ2xhaW0gbnVtYmVyIDIxIGlzIGRvY3VtZW50ZWQulGV1aCB9lGgij5QoaAdo+Wj2kGgkTnViLg==", + "assess__single_text_several_claims.json": "gASVBwMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UKGgAjAtBc3Nlc3NDbGFpbZSTlCmBlH2UKGgFfZQojAVjbGFpbZSMIldhdGVyIGJvaWxzIGF0IDEwMCBDIGF0IHNlYSBsZXZlbC6UjAhsYW5ndWFnZZSMAmVulIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwEaGlnaJSMEHZlcmlmaWNhdGlvbl91cmyUTowJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowRc3VnZ2VzdGVkX3Jld3JpdGWUTowKZXJyb3JfY29kZZROjBBjYW5kaWRhdGVfY2xhaW1zlF2UjBFpZGVudGlmaWVkX2NsYWltc5RdlIwEaGludJROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoDmgfaBhoG2gWaBBoFGgdaBJoF2gaaBmQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJoCimBlH2UKGgFfZQoaA6MG1RoZSBNb29uIGlzIG1hZGUgb2YgY2hlZXNlLpRoEIwCZW6UaBKMBUZhbHNllGgUjARoaWdolGgWTmgXTmgYTmgZTmgaTmgbXZRoHV2UaB9OdWggfZRoIo+UKGgOaB9oGGgbaBZoEGgUaB1oEmgXaBpoGZBoJE51YmgKKYGUfZQoaAV9lChoDowhVGhlIFBhY2lmaWMgaXMgdGhlIGRlZXBlc3Qgb2NlYW4ulGgQjAJlbpRoEowLTW9zdGx5IFRydWWUaBSMBm1lZGl1bZRoFk5oF05oGE5oGU5oGk5oG12UaB1dlGgfTnVoIH2UaCKPlChoDmgfaBhoG2gWaBBoFGgdaBJoF2gaaBmQaCROdWJljAVlcnJvcpROaBqMAJRoG12UjAttb3JlX2NsYWltc5RdlHVoIH2UaCKPlChoB2g+aDuQaCROdWIu", + "assess__suggest_rewrite.json": "gASVBwMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwOQXNzZXNzUmVzcG9uc2WUk5QpgZR9lCiMCF9fZGljdF9flH2UKIwGY2xhaW1zlF2UKGgAjAtBc3Nlc3NDbGFpbZSTlCmBlH2UKGgFfZQojAVjbGFpbZSMJ1ZlbnVzIGlzIHRoZSBjbG9zZXN0IHBsYW5ldCB0byB0aGUgU3VuLpSMCGxhbmd1YWdllIwCZW6UjAd2ZXJkaWN0lIwFRmFsc2WUjApjb25maWRlbmNllIwEaGlnaJSMEHZlcmlmaWNhdGlvbl91cmyUTowJcmF0aW9uYWxllIw1TWVyY3VyeSwgbm90IFZlbnVzLCBpcyB0aGUgY2xvc2VzdCBwbGFuZXQgdG8gdGhlIFN1bi6UjAdkaXNzZW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllIwpTWVyY3VyeSBpcyB0aGUgY2xvc2VzdCBwbGFuZXQgdG8gdGhlIFN1bi6UjAplcnJvcl9jb2RllE6MEGNhbmRpZGF0ZV9jbGFpbXOUXZSMEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE51jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgOaCFoGWgdaBZoEGgUaB9oEmgXaBxoGpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmgKKYGUfZQoaAV9lChoDowpTWVyY3VyeSBpcyB0aGUgY2xvc2VzdCBwbGFuZXQgdG8gdGhlIFN1bi6UaBCMAmVulGgSjARUcnVllGgUjARoaWdolGgWTmgXjCBNZXJjdXJ5IGlzIHRoZSBpbm5lcm1vc3QgcGxhbmV0LpRoGU5oGk5oHE5oHV2UaB9dlGghTnVoIn2UaCSPlChoDmghaBloHWgWaBBoFGgfaBJoF2gcaBqQaCZOdWJljAVlcnJvcpROaByMAJRoHV2UjAttb3JlX2NsYWltc5RdlHVoIn2UaCSPlChoB2g2aDOQaCZOdWIu", + "citecheck__get_checking.json": "gASV7AYAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwIY2hlY2tpbmeUjAdvdXRjb21llE6MCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUTowScG9sbF9hZnRlcl9zZWNvbmRzlEsKjAZwb2xpY3mUaACMD0NpdGVjaGVja1BvbGljeZSTlCmBlH2UKGgFfZSMDW1heF9jaXRhdGlvbnOUSwJzjBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgWkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjBBDaXRlY2hlY2tTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NpdGF0aW9uc19mb3VuZJRLAowSY2l0YXRpb25zX3NlbGVjdGVklEsCjA5jaXRhdGlvbl9saW1pdJRLAowWY2l0YXRpb25fbGltaXRfcmVhY2hlZJSJjA9jaXRhdGlvbl9jaGVja3OUaACMGVJldmlld0NpdGF0aW9uQ2hlY2tDb3VudHOUk5QpgZR9lChoBX2UKIwHY2hlY2tlZJRLAIwJdW5jaGVja2VklEsAjAZmYWlsZWSUSwB1aBd9lGgZj5QoaCxoLWgukGgbTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwB1aBd9lGgZj5QoaCNoJWgxaCRoJmgikGgbTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAHNoF32UaBmPlChoOpBoG051YowJY2l0YXRpb25zlF2UKGgAjA5SZXZpZXdDaXRhdGlvbpSTlCmBlH2UKGgFfZQojAVpbmRleJRLAIwJcmVmZXJlbmNllIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMCWNpdGVkX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjANkb2mUTowJc3RhdGVtZW50lIwiVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LpSMBnF1b3Rlc5RdlIwIcG9zaXRpb26UTowGcmVzdWx0lE6MBWNoZWNrlGgAjBNSZXZpZXdDaXRhdGlvbkNoZWNrlJOUKYGUfZQoaAV9lChoCYwHcGVuZGluZ5SMCXBhZ2VfcmVhZJROjApwYWdlX3RpdGxllE6ME3BhZ2VfcHVibGlzaGVkX2RhdGWUTowNcGFnZV9sYW5ndWFnZZROjApzb3VyY2VfdXJslE6MDnNvdXJjZV92ZXJzaW9ulE6MB3N1cHBvcnSUTowHc25pcHBldJROjAlyYXRpb25hbGWUTowFcXVvdGWUTowNbWlzc2luZ19xdW90ZZROjA5kb2lfcmVnaXN0ZXJlZJROjAhtZXRhZGF0YZROjBRtZXRhZGF0YV9kaWZmZXJlbmNlc5RdlIwKcmVnaXN0ZXJlZJROjBB1bmNoZWNrZWRfcmVhc29ulE6MBGhpbnSUTowHZmFpbHVyZZROdWgXfZRoGY+UKGhZaGdoX2haaFtoaGhiaGNoCWhhaGRoYGhYaGZoXWhXaFxoXmhpkGgbTnVidWgXfZRoGY+UKGhKaE9oRWhQaERoSWhMaEdoTpBoG051YmhAKYGUfZQoaAV9lChoREsBaEWMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGhHjB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRoSU5oSowiVGhlIGFnZW5jeSBzYWlkIHNvIGluIGEgc3RhdGVtZW50LpRoTF2UaE5OaE9OaFBoUimBlH2UKGgFfZQoaAmMB3BlbmRpbmeUaFdOaFhOaFlOaFpOaFtOaFxOaF1OaF5OaF9OaGBOaGFOaGJOaGNOaGRdlGhmTmhnTmhoTmhpTnVoF32UaBmPlChoWWhnaF9oWmhbaGhoYmhjaAloYWhkaGBoWGhmaF1oV2hcaF5oaZBoG051YnVoF32UaBmPlChoSmhPaEVoUGhEaEloTGhHaE6QaBtOdWJlaDFdlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMDm1vcmVfY2l0YXRpb25zlF2UaGlOdWgXfZSMCGxhbmd1YWdllIwCZW6Uc2gZj5QoaAtoNGgOaAxohGgJaBBoPWgxaH9oD2gHaBxogWhpkGgbTnViLg==", + "citecheck__get_completed_clean.json": "gASV0QgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROjAZwb2xpY3mUaACMD0NpdGVjaGVja1BvbGljeZSTlCmBlH2UKGgFfZSMDW1heF9jaXRhdGlvbnOUSwJzjBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgYkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjBBDaXRlY2hlY2tTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NpdGF0aW9uc19mb3VuZJRLAowSY2l0YXRpb25zX3NlbGVjdGVklEsCjA5jaXRhdGlvbl9saW1pdJRLAowWY2l0YXRpb25fbGltaXRfcmVhY2hlZJSJjA9jaXRhdGlvbl9jaGVja3OUaACMGVJldmlld0NpdGF0aW9uQ2hlY2tDb3VudHOUk5QpgZR9lChoBX2UKIwHY2hlY2tlZJRLAowJdW5jaGVja2VklEsAjAZmYWlsZWSUSwB1aBl9lGgbj5QoaC5oL2gwkGgdTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwB1aBl9lGgbj5QoaCVoJ2gzaCZoKGgkkGgdTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoGX2UaBuPlChoPJBoHU51YowJY2l0YXRpb25zlF2UKGgAjA5SZXZpZXdDaXRhdGlvbpSTlCmBlH2UKGgFfZQojAVpbmRleJRLAIwJcmVmZXJlbmNllIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMCWNpdGVkX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjANkb2mUTowJc3RhdGVtZW50lIwiVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LpSMBnF1b3Rlc5RdlIwIcG9zaXRpb26UTowGcmVzdWx0lGgAjBRSZXZpZXdDaXRhdGlvblJlc3VsdJSTlCmBlH2UKGgFfZQojAdmaW5kaW5nlIwJc3VwcG9ydGVklIwGc291cmNllIwHc3VwcG9ydJSMCGlzX2lzc3VllIl1aBl9lGgbj5QoaFdoW2hZkGgdTnVijAVjaGVja5RoAIwTUmV2aWV3Q2l0YXRpb25DaGVja5STlCmBlH2UKGgFfZQoaAmMCWNvbXBsZXRlZJSMCXBhZ2VfcmVhZJSMBGZ1bGyUjApwYWdlX3RpdGxllIwnUGFnZSBhdCBodHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwTcGFnZV9wdWJsaXNoZWRfZGF0ZZROjA1wYWdlX2xhbmd1YWdllIwCZW6UjApzb3VyY2VfdXJslIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMDnNvdXJjZV92ZXJzaW9ulE6MB3N1cHBvcnSUjAlzdXBwb3J0ZWSUjAdzbmlwcGV0lIwTVGhlIHNvdXJjZSBzYXlzIHNvLpSMCXJhdGlvbmFsZZSME1RoZSBwYWdlIHN0YXRlcyBpdC6UjAVxdW90ZZROjA1taXNzaW5nX3F1b3RllE6MDmRvaV9yZWdpc3RlcmVklE6MCG1ldGFkYXRhlE6MFG1ldGFkYXRhX2RpZmZlcmVuY2VzlF2UjApyZWdpc3RlcmVklE6MEHVuY2hlY2tlZF9yZWFzb26UTowEaGludJROjAdmYWlsdXJllE51aBl9lGgbj5QoaGlofGhzaGpobGh9aHdoeGgJaHZoeWh1aGdoe2hvaGVobmhxaH6QaB1OdWJ1aBl9lGgbj5QoaExoUWhHaF5oRmhLaE5oSWhQkGgdTnViaEIpgZR9lChoBX2UKGhGSwFoR4wdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaEmMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGhLTmhMjCJUaGUgYWdlbmN5IHNhaWQgc28gaW4gYSBzdGF0ZW1lbnQulGhOXZRoUE5oUWhTKYGUfZQoaAV9lChoV4wJc3VwcG9ydGVklGhZjAdzdXBwb3J0lGhbiXVoGX2UaBuPlChoV2hbaFmQaB1OdWJoXmhgKYGUfZQoaAV9lChoCYwJY29tcGxldGVklGhljARmdWxslGhnjCVQYWdlIGF0IGh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGhpTmhqjAJlbpRobIwdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaG5OaG+MCXN1cHBvcnRlZJRocYwTVGhlIHNvdXJjZSBzYXlzIHNvLpRoc4wTVGhlIHBhZ2Ugc3RhdGVzIGl0LpRodU5odk5od05oeE5oeV2UaHtOaHxOaH1OaH5OdWgZfZRoG4+UKGhpaHxoc2hqaGxofWh3aHhoCWh2aHlodWhnaHtob2hlaG5ocWh+kGgdTnVidWgZfZRoG4+UKGhMaFFoR2heaEZoS2hOaEloUJBoHU51YmVoM12UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRofk51aBl9lIwIbGFuZ3VhZ2WUjAJlbpRzaBuPlChoC2g2aA9oDWinaAloEmg/aDNoomgRaAdoHmikaH6QaB1OdWIu", + "citecheck__get_completed_doi_pair.json": "gASVrAYAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROjAZwb2xpY3mUaACMD0NpdGVjaGVja1BvbGljeZSTlCmBlH2UKGgFfZSMDW1heF9jaXRhdGlvbnOUSwFzjBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgYkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjBBDaXRlY2hlY2tTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NpdGF0aW9uc19mb3VuZJRLAYwSY2l0YXRpb25zX3NlbGVjdGVklEsBjA5jaXRhdGlvbl9saW1pdJRLAYwWY2l0YXRpb25fbGltaXRfcmVhY2hlZJSJjA9jaXRhdGlvbl9jaGVja3OUaACMGVJldmlld0NpdGF0aW9uQ2hlY2tDb3VudHOUk5QpgZR9lChoBX2UKIwHY2hlY2tlZJRLAYwJdW5jaGVja2VklEsAjAZmYWlsZWSUSwB1aBl9lGgbj5QoaC5oL2gwkGgdTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwB1aBl9lGgbj5QoaCVoJ2gzaCZoKGgkkGgdTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAXNoGX2UaBuPlChoPJBoHU51YowJY2l0YXRpb25zlF2UaACMDlJldmlld0NpdGF0aW9ulJOUKYGUfZQoaAV9lCiMBWluZGV4lEsAjAlyZWZlcmVuY2WUjBMxMC4xMDM4L25hdHVyZTEyMzczlIwJY2l0ZWRfdXJslIwjaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvbmF0dXJlMTIzNzOUjANkb2mUjBMxMC4xMDM4L25hdHVyZTEyMzczlIwJc3RhdGVtZW50lIwmRGlhbW9uZCBzZW5zb3JzIG1lYXN1cmUgaGVhdCBpbiBjZWxscy6UjAZxdW90ZXOUXZSMCHBvc2l0aW9ulE6MBnJlc3VsdJRoAIwUUmV2aWV3Q2l0YXRpb25SZXN1bHSUk5QpgZR9lChoBX2UKIwHZmluZGluZ5SMCXN1cHBvcnRlZJSMBnNvdXJjZZSMB3N1cHBvcnSUjAhpc19pc3N1ZZSJdWgZfZRoG4+UKGhYaFxoWpBoHU51YowFY2hlY2uUaACME1Jldmlld0NpdGF0aW9uQ2hlY2uUk5QpgZR9lChoBX2UKGgJjAljb21wbGV0ZWSUjAlwYWdlX3JlYWSUjARmdWxslIwKcGFnZV90aXRsZZSMDFBhZ2UgYXQgTm9uZZSME3BhZ2VfcHVibGlzaGVkX2RhdGWUTowNcGFnZV9sYW5ndWFnZZSMAmVulIwKc291cmNlX3VybJROjA5zb3VyY2VfdmVyc2lvbpROjAdzdXBwb3J0lIwJc3VwcG9ydGVklIwHc25pcHBldJSME1RoZSBzb3VyY2Ugc2F5cyBzby6UjAlyYXRpb25hbGWUjBNUaGUgcGFnZSBzdGF0ZXMgaXQulIwFcXVvdGWUTowNbWlzc2luZ19xdW90ZZROjA5kb2lfcmVnaXN0ZXJlZJROjAhtZXRhZGF0YZROjBRtZXRhZGF0YV9kaWZmZXJlbmNlc5RdlIwKcmVnaXN0ZXJlZJROjBB1bmNoZWNrZWRfcmVhc29ulE6MBGhpbnSUTowHZmFpbHVyZZROdWgZfZRoG4+UKGhqaHxoc2hraG1ofWh3aHhoCWh2aHlodWhoaHtob2hmaG5ocWh+kGgdTnVidWgZfZRoG4+UKGhNaFJoR2hfaEZoS2hPaEloUZBoHU51YmFoM12UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRofk51aBl9lIwIbGFuZ3VhZ2WUjAJlbpRzaBuPlChoC2g2aA9oDWiJaAloEmg/aDNohGgRaAdoHmiGaH6QaB1OdWIu", + "citecheck__get_completed_incomplete.json": "gASVXQoAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMCmluY29tcGxldGWUjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lIwbMjAyNi0xMC0wMVQxMDowNzowMC4xMjM0NTZalIwScG9sbF9hZnRlcl9zZWNvbmRzlE6MBnBvbGljeZRoAIwPQ2l0ZWNoZWNrUG9saWN5lJOUKYGUfZQoaAV9lIwNbWF4X2NpdGF0aW9uc5RLAnOMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBiQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMEENpdGVjaGVja1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2l0YXRpb25zX2ZvdW5klEsCjBJjaXRhdGlvbnNfc2VsZWN0ZWSUSwKMDmNpdGF0aW9uX2xpbWl0lEsCjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklImMD2NpdGF0aW9uX2NoZWNrc5RoAIwZUmV2aWV3Q2l0YXRpb25DaGVja0NvdW50c5STlCmBlH2UKGgFfZQojAdjaGVja2VklEsBjAl1bmNoZWNrZWSUSwCMBmZhaWxlZJRLAXVoGX2UaBuPlChoLmgvaDCQaB1OdWKMD2NpdGF0aW9uX2lzc3Vlc5RLAHVoGX2UaBuPlChoJWgnaDNoJmgoaCSQaB1OdWKMB2NyZWRpdHOUaACMDVJldmlld0NyZWRpdHOUk5QpgZR9lChoBX2UjAdjaGFyZ2VklEsBc2gZfZRoG4+UKGg8kGgdTnVijAljaXRhdGlvbnOUXZQoaACMDlJldmlld0NpdGF0aW9ulJOUKYGUfZQoaAV9lCiMBWluZGV4lEsAjAlyZWZlcmVuY2WUjB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwJY2l0ZWRfdXJslIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMA2RvaZROjAlzdGF0ZW1lbnSUjCJVbmVtcGxveW1lbnQgZmVsbCB0byA0LjElIGluIDIwMjQulIwGcXVvdGVzlF2UjAhwb3NpdGlvbpROjAZyZXN1bHSUaACMFFJldmlld0NpdGF0aW9uUmVzdWx0lJOUKYGUfZQoaAV9lCiMB2ZpbmRpbmeUjAlzdXBwb3J0ZWSUjAZzb3VyY2WUjAdzdXBwb3J0lIwIaXNfaXNzdWWUiXVoGX2UaBuPlChoV2hbaFmQaB1OdWKMBWNoZWNrlGgAjBNSZXZpZXdDaXRhdGlvbkNoZWNrlJOUKYGUfZQoaAV9lChoCYwJY29tcGxldGVklIwJcGFnZV9yZWFklIwEZnVsbJSMCnBhZ2VfdGl0bGWUjCdQYWdlIGF0IGh0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjBNwYWdlX3B1Ymxpc2hlZF9kYXRllE6MDXBhZ2VfbGFuZ3VhZ2WUjAJlbpSMCnNvdXJjZV91cmyUjB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwOc291cmNlX3ZlcnNpb26UTowHc3VwcG9ydJSMCXN1cHBvcnRlZJSMB3NuaXBwZXSUjBNUaGUgc291cmNlIHNheXMgc28ulIwJcmF0aW9uYWxllIwTVGhlIHBhZ2Ugc3RhdGVzIGl0LpSMBXF1b3RllE6MDW1pc3NpbmdfcXVvdGWUTowOZG9pX3JlZ2lzdGVyZWSUTowIbWV0YWRhdGGUTowUbWV0YWRhdGFfZGlmZmVyZW5jZXOUXZSMCnJlZ2lzdGVyZWSUTowQdW5jaGVja2VkX3JlYXNvbpROjARoaW50lE6MB2ZhaWx1cmWUTnVoGX2UaBuPlChoaWh8aHNoamhsaH1od2h4aAlodmh5aHVoZ2h7aG9oZWhuaHFofpBoHU51YnVoGX2UaBuPlChoTGhRaEdoXmhGaEtoTmhJaFCQaB1OdWJoQimBlH2UKGgFfZQoaEZLAWhHjB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRoSYwdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaEtOaEyMIlRoZSBhZ2VuY3kgc2FpZCBzbyBpbiBhIHN0YXRlbWVudC6UaE5dlGhQTmhRTmheaGApgZR9lChoBX2UKGgJjAZmYWlsZWSUaGVOaGdOaGlOaGpOaGxOaG5OaG9OaHFOaHNOaHVOaHZOaHdOaHhOaHldlGh7Tmh8Tmh9jC5UaGUgY2hlY2sgZmFpbGVkIG9uIG91ciBzaWRlLiBUcnkgYWdhaW4gbGF0ZXIulGh+aACMDEZhaWx1cmVCbG9ja5STlCmBlH2UKGgFfZQojA5mYWlsdXJlX3JlYXNvbpSMCGludGVybmFslIwNZmFpbHVyZV9jbGFzc5SMCGludGVybmFslIwJcmV0cnlhYmxllIlofYwuVGhlIGNoZWNrIGZhaWxlZCBvbiBvdXIgc2lkZS4gVHJ5IGFnYWluIGxhdGVyLpSMCGRvY3NfdXJslIwkaHR0cHM6Ly9sZW56LmlvL2RvY3MvZXJyb3JzI2ludGVybmFslHVoGX2UaBuPlChofWiVaJtol2iZkGgdTnVidWgZfZRoG4+UKGhpaHxoc2hqaGxofWh3aHhoCWh2aHlodWhnaHtob2hlaG5ocWh+kGgdTnVidWgZfZRoG4+UKGhMaFFoR2heaEZoS2hOaEloUJBoHU51YmVoM12UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlGgAjBVSZXZpZXdDaXRhdGlvbkZhaWx1cmWUk5QpgZR9lChoBX2UKIwOY2l0YXRpb25faW5kZXiUSwFoR4wdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaEmMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGhLTmh+aJEpgZR9lChoBX2UKGiVjAhpbnRlcm5hbJRol4wIaW50ZXJuYWyUaJmJaH2MLlRoZSBjaGVjayBmYWlsZWQgb24gb3VyIHNpZGUuIFRyeSBhZ2FpbiBsYXRlci6UaJuMJGh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyNpbnRlcm5hbJR1aBl9lGgbj5QoaH1olWibaJdomZBoHU51YnVoGX2UaBuPlChoR2hLaKtoSWh+kGgdTnViYYwObW9yZV9jaXRhdGlvbnOUXZRofk51aBl9lIwIbGFuZ3VhZ2WUjAJlbpRzaBuPlChoC2g2aA9oDWi8aAloEmg/aDNopGgRaAdoHmi5aH6QaB1OdWIu", + "citecheck__get_completed_issues_found.json": "gASVGgsAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMDGlzc3Vlc19mb3VuZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjBJwb2xsX2FmdGVyX3NlY29uZHOUTowGcG9saWN5lGgAjA9DaXRlY2hlY2tQb2xpY3mUk5QpgZR9lChoBX2UjA1tYXhfY2l0YXRpb25zlEsUc4wSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGJCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwQQ2l0ZWNoZWNrU3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAowOY2l0YXRpb25fbGltaXSUSxSMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwKMCXVuY2hlY2tlZJRLAIwGZmFpbGVklEsAdWgZfZRoG4+UKGguaC9oMJBoHU51YowPY2l0YXRpb25faXNzdWVzlEsBdWgZfZRoG4+UKGglaCdoM2gmaChoJJBoHU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwJzaBl9lGgbj5QoaDyQaB1OdWKMCWNpdGF0aW9uc5RdlChoAIwOUmV2aWV3Q2l0YXRpb26Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMCXJlZmVyZW5jZZSMGmEgcmVwb3J0IGZyb20gdGhlIG1pbmlzdHJ5lIwJY2l0ZWRfdXJslIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMA2RvaZROjAlzdGF0ZW1lbnSUjEtVbmVtcGxveW1lbnQgZmVsbCB0byA0LjElIGluIDIwMjQsIGFjY29yZGluZyB0byBhIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeS6UjAZxdW90ZXOUXZSMCHBvc2l0aW9ulGgAjAhQb3NpdGlvbpSTlCmBlH2UKGgFfZQojAVzdGFydJRLAIwDZW5klEtujAR0ZXh0lE51aBl9lGgbj5QoaFZoV2hYkGgdTnVijAZyZXN1bHSUaACMFFJldmlld0NpdGF0aW9uUmVzdWx0lJOUKYGUfZQoaAV9lCiMB2ZpbmRpbmeUjAxjb250cmFkaWN0ZWSUjAZzb3VyY2WUjAdzdXBwb3J0lIwIaXNfaXNzdWWUiHVoGX2UaBuPlChoYWhlaGOQaB1OdWKMBWNoZWNrlGgAjBNSZXZpZXdDaXRhdGlvbkNoZWNrlJOUKYGUfZQoaAV9lChoCYwJY29tcGxldGVklIwJcGFnZV9yZWFklIwEZnVsbJSMCnBhZ2VfdGl0bGWUjCdQYWdlIGF0IGh0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjBNwYWdlX3B1Ymxpc2hlZF9kYXRllE6MDXBhZ2VfbGFuZ3VhZ2WUjAJlbpSMCnNvdXJjZV91cmyUjB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwOc291cmNlX3ZlcnNpb26UTowHc3VwcG9ydJSMDGNvbnRyYWRpY3RlZJSMB3NuaXBwZXSUjBNUaGUgc291cmNlIHNheXMgc28ulIwJcmF0aW9uYWxllIwTVGhlIHBhZ2Ugc3RhdGVzIGl0LpSMBXF1b3RllE6MDW1pc3NpbmdfcXVvdGWUTowOZG9pX3JlZ2lzdGVyZWSUTowIbWV0YWRhdGGUTowUbWV0YWRhdGFfZGlmZmVyZW5jZXOUXZSMCnJlZ2lzdGVyZWSUTowQdW5jaGVja2VkX3JlYXNvbpROjARoaW50lE6MB2ZhaWx1cmWUTnVoGX2UaBuPlChoc2iGaH1odGh2aIdogWiCaAlogGiDaH9ocWiFaHlob2h4aHtoiJBoHU51YnVoGX2UaBuPlChoTGhbaEdoaGhGaEtoTmhJaFCQaB1OdWJoQimBlH2UKGgFfZQoaEZLAWhHjAthIHN0YXRlbWVudJRoSYwdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaEtOaEyMIlRoZSBhZ2VuY3kgc2FpZCBzbyBpbiBhIHN0YXRlbWVudC6UaE5dlGhQaFIpgZR9lChoBX2UKGhWS29oV0uyaFhOdWgZfZRoG4+UKGhWaFdoWJBoHU51YmhbaF0pgZR9lChoBX2UKGhhjAlzdXBwb3J0ZWSUaGOMB3N1cHBvcnSUaGWJdWgZfZRoG4+UKGhhaGVoY5BoHU51YmhoaGopgZR9lChoBX2UKGgJjAljb21wbGV0ZWSUaG+MBGZ1bGyUaHGMJVBhZ2UgYXQgaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaHNOaHSMAmVulGh2jB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRoeE5oeYwJc3VwcG9ydGVklGh7jBNUaGUgc291cmNlIHNheXMgc28ulGh9jBNUaGUgcGFnZSBzdGF0ZXMgaXQulGh/TmiATmiBTmiCTmiDXZRohU5ohk5oh05oiE51aBl9lGgbj5QoaHNohmh9aHRodmiHaIFogmgJaIBog2h/aHFohWh5aG9oeGh7aIiQaB1OdWJ1aBl9lGgbj5QoaExoW2hHaGhoRmhLaE5oSWhQkGgdTnViZWgzXZRoAIwTUmV2aWV3Q2l0YXRpb25Jc3N1ZZSTlCmBlH2UKGgFfZQojA5jaXRhdGlvbl9pbmRleJRLAGhHjBphIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeZRoSYwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJRoS05oTIxLVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LCBhY2NvcmRpbmcgdG8gYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnkulGhOXZRoUGhSKYGUfZQoaAV9lChoVksAaFdLbmhYTnVoGX2UaBuPlChoVmhXaFiQaB1OdWJoYYwMY29udHJhZGljdGVklGhjjAdzdXBwb3J0lGh7jBNUaGUgc291cmNlIHNheXMgc28ulGh9jBNUaGUgcGFnZSBzdGF0ZXMgaXQulGiATmiDXZRocYwnUGFnZSBhdCBodHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lGiITnVoGX2UaBuPlChoTGiAaEdog2hxaEtotmh9aE5oY2hhaEloe2iIaFCQaB1OdWJhjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRoiE51aBl9lIwIbGFuZ3VhZ2WUjAJlbpRzaBuPlChoC2g2aA9oDWjNaAloEmg/aDNoyGgRaAdoHmjKaIiQaB1OdWIu", + "citecheck__get_completed_partly_supported.json": "gASV3wgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROjAZwb2xpY3mUaACMD0NpdGVjaGVja1BvbGljeZSTlCmBlH2UKGgFfZSMDW1heF9jaXRhdGlvbnOUSwJzjBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgYkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjBBDaXRlY2hlY2tTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NpdGF0aW9uc19mb3VuZJRLAowSY2l0YXRpb25zX3NlbGVjdGVklEsCjA5jaXRhdGlvbl9saW1pdJRLAowWY2l0YXRpb25fbGltaXRfcmVhY2hlZJSJjA9jaXRhdGlvbl9jaGVja3OUaACMGVJldmlld0NpdGF0aW9uQ2hlY2tDb3VudHOUk5QpgZR9lChoBX2UKIwHY2hlY2tlZJRLAowJdW5jaGVja2VklEsAjAZmYWlsZWSUSwB1aBl9lGgbj5QoaC5oL2gwkGgdTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwB1aBl9lGgbj5QoaCVoJ2gzaCZoKGgkkGgdTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoGX2UaBuPlChoPJBoHU51YowJY2l0YXRpb25zlF2UKGgAjA5SZXZpZXdDaXRhdGlvbpSTlCmBlH2UKGgFfZQojAVpbmRleJRLAIwJcmVmZXJlbmNllIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMCWNpdGVkX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjANkb2mUTowJc3RhdGVtZW50lIwiVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LpSMBnF1b3Rlc5RdlIwIcG9zaXRpb26UTowGcmVzdWx0lGgAjBRSZXZpZXdDaXRhdGlvblJlc3VsdJSTlCmBlH2UKGgFfZQojAdmaW5kaW5nlIwQcGFydGx5X3N1cHBvcnRlZJSMBnNvdXJjZZSMB3N1cHBvcnSUjAhpc19pc3N1ZZSJdWgZfZRoG4+UKGhXaFtoWZBoHU51YowFY2hlY2uUaACME1Jldmlld0NpdGF0aW9uQ2hlY2uUk5QpgZR9lChoBX2UKGgJjAljb21wbGV0ZWSUjAlwYWdlX3JlYWSUjARmdWxslIwKcGFnZV90aXRsZZSMJ1BhZ2UgYXQgaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSME3BhZ2VfcHVibGlzaGVkX2RhdGWUTowNcGFnZV9sYW5ndWFnZZSMAmVulIwKc291cmNlX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjA5zb3VyY2VfdmVyc2lvbpROjAdzdXBwb3J0lIwQcGFydGx5X3N1cHBvcnRlZJSMB3NuaXBwZXSUjBNUaGUgc291cmNlIHNheXMgc28ulIwJcmF0aW9uYWxllIwTVGhlIHBhZ2Ugc3RhdGVzIGl0LpSMBXF1b3RllE6MDW1pc3NpbmdfcXVvdGWUTowOZG9pX3JlZ2lzdGVyZWSUTowIbWV0YWRhdGGUTowUbWV0YWRhdGFfZGlmZmVyZW5jZXOUXZSMCnJlZ2lzdGVyZWSUTowQdW5jaGVja2VkX3JlYXNvbpROjARoaW50lE6MB2ZhaWx1cmWUTnVoGX2UaBuPlChoaWh8aHNoamhsaH1od2h4aAlodmh5aHVoZ2h7aG9oZWhuaHFofpBoHU51YnVoGX2UaBuPlChoTGhRaEdoXmhGaEtoTmhJaFCQaB1OdWJoQimBlH2UKGgFfZQoaEZLAWhHjB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRoSYwdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaEtOaEyMIlRoZSBhZ2VuY3kgc2FpZCBzbyBpbiBhIHN0YXRlbWVudC6UaE5dlGhQTmhRaFMpgZR9lChoBX2UKGhXjAlzdXBwb3J0ZWSUaFmMB3N1cHBvcnSUaFuJdWgZfZRoG4+UKGhXaFtoWZBoHU51YmheaGApgZR9lChoBX2UKGgJjAljb21wbGV0ZWSUaGWMBGZ1bGyUaGeMJVBhZ2UgYXQgaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaGlOaGqMAmVulGhsjB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRobk5ob4wJc3VwcG9ydGVklGhxjBNUaGUgc291cmNlIHNheXMgc28ulGhzjBNUaGUgcGFnZSBzdGF0ZXMgaXQulGh1Tmh2Tmh3Tmh4Tmh5XZRoe05ofE5ofU5ofk51aBl9lGgbj5QoaGlofGhzaGpobGh9aHdoeGgJaHZoeWh1aGdoe2hvaGVobmhxaH6QaB1OdWJ1aBl9lGgbj5QoaExoUWhHaF5oRmhLaE5oSWhQkGgdTnViZWgzXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjA5tb3JlX2NpdGF0aW9uc5RdlGh+TnVoGX2UjAhsYW5ndWFnZZSMAmVulHNoG4+UKGgLaDZoD2gNaKdoCWgSaD9oM2iiaBFoB2geaKRofpBoHU51Yi4=", + "citecheck__get_completed_unchecked.json": "gASVqwgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMCXVuY2hlY2tlZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjBJwb2xsX2FmdGVyX3NlY29uZHOUTowGcG9saWN5lGgAjA9DaXRlY2hlY2tQb2xpY3mUk5QpgZR9lChoBX2UjA1tYXhfY2l0YXRpb25zlEsCc4wSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGJCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwQQ2l0ZWNoZWNrU3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAowOY2l0YXRpb25fbGltaXSUSwKMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwCMCXVuY2hlY2tlZJRLAowGZmFpbGVklEsAdWgZfZRoG4+UKGguaC9oMJBoHU51YowPY2l0YXRpb25faXNzdWVzlEsAdWgZfZRoG4+UKGglaCdoM2gmaChoJJBoHU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwBzaBl9lGgbj5QoaDyQaB1OdWKMCWNpdGF0aW9uc5RdlChoAIwOUmV2aWV3Q2l0YXRpb26Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMCXJlZmVyZW5jZZSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjAljaXRlZF91cmyUjB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwDZG9plE6MCXN0YXRlbWVudJSMIlVuZW1wbG95bWVudCBmZWxsIHRvIDQuMSUgaW4gMjAyNC6UjAZxdW90ZXOUXZSMCHBvc2l0aW9ulE6MBnJlc3VsdJRoAIwUUmV2aWV3Q2l0YXRpb25SZXN1bHSUk5QpgZR9lChoBX2UKIwHZmluZGluZ5SMCXVuY2hlY2tlZJSMBnNvdXJjZZROjAhpc19pc3N1ZZSJdWgZfZRoG4+UKGhXaFpoWZBoHU51YowFY2hlY2uUaACME1Jldmlld0NpdGF0aW9uQ2hlY2uUk5QpgZR9lChoBX2UKGgJjAljb21wbGV0ZWSUjAlwYWdlX3JlYWSUjARmdWxslIwKcGFnZV90aXRsZZSMJ1BhZ2UgYXQgaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSME3BhZ2VfcHVibGlzaGVkX2RhdGWUTowNcGFnZV9sYW5ndWFnZZSMAmVulIwKc291cmNlX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjA5zb3VyY2VfdmVyc2lvbpROjAdzdXBwb3J0lIwJdW5jaGVja2VklIwHc25pcHBldJROjAlyYXRpb25hbGWUjBNUaGUgcGFnZSBzdGF0ZXMgaXQulIwFcXVvdGWUTowNbWlzc2luZ19xdW90ZZROjA5kb2lfcmVnaXN0ZXJlZJROjAhtZXRhZGF0YZROjBRtZXRhZGF0YV9kaWZmZXJlbmNlc5RdlIwKcmVnaXN0ZXJlZJROjBB1bmNoZWNrZWRfcmVhc29ulIwHbm9fdGV4dJSMBGhpbnSUTowHZmFpbHVyZZROdWgZfZRoG4+UKGhoaHpocWhpaGtofGh1aHZoCWh0aHdoc2hmaHlobmhkaG1ocGh9kGgdTnVidWgZfZRoG4+UKGhMaFFoR2hdaEZoS2hOaEloUJBoHU51YmhCKYGUfZQoaAV9lChoRksBaEeMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGhJjB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRoS05oTIwiVGhlIGFnZW5jeSBzYWlkIHNvIGluIGEgc3RhdGVtZW50LpRoTl2UaFBOaFFoUymBlH2UKGgFfZQoaFeMCXVuY2hlY2tlZJRoWU5oWol1aBl9lGgbj5QoaFdoWmhZkGgdTnViaF1oXymBlH2UKGgFfZQoaAmMCWNvbXBsZXRlZJRoZIwEZnVsbJRoZowlUGFnZSBhdCBodHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRoaE5oaYwCZW6UaGuMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGhtTmhujAl1bmNoZWNrZWSUaHBOaHGME1RoZSBwYWdlIHN0YXRlcyBpdC6UaHNOaHROaHVOaHZOaHddlGh5Tmh6jAdub190ZXh0lGh8Tmh9TnVoGX2UaBuPlChoaGh6aHFoaWhraHxodWh2aAlodGh3aHNoZmh5aG5oZGhtaHBofZBoHU51YnVoGX2UaBuPlChoTGhRaEdoXWhGaEtoTmhJaFCQaB1OdWJlaDNdlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMDm1vcmVfY2l0YXRpb25zlF2UaH1OdWgZfZSMCGxhbmd1YWdllIwCZW6Uc2gbj5QoaAtoNmgPaA1opWgJaBJoP2gzaKBoEWgHaB5oomh9kGgdTnViLg==", + "citecheck__get_failed_no_citations.json": "gASVFAQAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwGZmFpbGVklIwHb3V0Y29tZZSMCXVuY2hlY2tlZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjBJwb2xsX2FmdGVyX3NlY29uZHOUTowGcG9saWN5lGgAjA9DaXRlY2hlY2tQb2xpY3mUk5QpgZR9lChoBX2UjA1tYXhfY2l0YXRpb25zlEsUc4wSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGJCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwQQ2l0ZWNoZWNrU3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lEsUjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwB1aBl9lGgbj5QoaCVoJ2gpaCZoKGgkkGgdTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAHNoGX2UaBuPlChoMpBoHU51YowJY2l0YXRpb25zlF2UaCldlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMDm1vcmVfY2l0YXRpb25zlE6MB2ZhaWx1cmWUaACMDEZhaWx1cmVCbG9ja5STlCmBlH2UKGgFfZQojA5mYWlsdXJlX3JlYXNvbpSMDG5vX2NpdGF0aW9uc5SMDWZhaWx1cmVfY2xhc3OUjA1pbnZhbGlkX2lucHV0lIwJcmV0cnlhYmxllImMBGhpbnSUjE9UaGUgdGV4dCBoYXMgbm8gY2l0YXRpb24gdG8gY2hlY2s6IG5vIGxpbmssIERPSSBvciBudW1iZXJlZCByZWZlcmVuY2Ugd2l0aCBvbmUulIwIZG9jc191cmyUjClodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjaW52YWxpZC1pbnB1dJR1aBl9lGgbj5QoaEZoQWhIaENoRZBoHU51YnVoGX2UjAhsYW5ndWFnZZSMAmVulHNoG4+UKGgLaCxoD2gNaE1oCWgSaDVoKWg4aBFoB2geaDpoO5BoHU51Yi4=", + "citecheck__get_failed_upstream_unavailable.json": "gASVQAwAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwGZmFpbGVklIwHb3V0Y29tZZSMCXVuY2hlY2tlZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjBJwb2xsX2FmdGVyX3NlY29uZHOUTowGcG9saWN5lGgAjA9DaXRlY2hlY2tQb2xpY3mUk5QpgZR9lChoBX2UjA1tYXhfY2l0YXRpb25zlEsUc4wSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGJCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwQQ2l0ZWNoZWNrU3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAowOY2l0YXRpb25fbGltaXSUSxSMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwCMCXVuY2hlY2tlZJRLAIwGZmFpbGVklEsCdWgZfZRoG4+UKGguaC9oMJBoHU51YowPY2l0YXRpb25faXNzdWVzlEsAdWgZfZRoG4+UKGglaCdoM2gmaChoJJBoHU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwBzaBl9lGgbj5QoaDyQaB1OdWKMCWNpdGF0aW9uc5RdlChoAIwOUmV2aWV3Q2l0YXRpb26Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMCXJlZmVyZW5jZZSMGmEgcmVwb3J0IGZyb20gdGhlIG1pbmlzdHJ5lIwJY2l0ZWRfdXJslIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMA2RvaZROjAlzdGF0ZW1lbnSUTowGcXVvdGVzlF2UjAhwb3NpdGlvbpROjAZyZXN1bHSUTowFY2hlY2uUaACME1Jldmlld0NpdGF0aW9uQ2hlY2uUk5QpgZR9lChoBX2UKGgJjAZmYWlsZWSUjAlwYWdlX3JlYWSUTowKcGFnZV90aXRsZZROjBNwYWdlX3B1Ymxpc2hlZF9kYXRllE6MDXBhZ2VfbGFuZ3VhZ2WUTowKc291cmNlX3VybJROjA5zb3VyY2VfdmVyc2lvbpROjAdzdXBwb3J0lE6MB3NuaXBwZXSUTowJcmF0aW9uYWxllE6MBXF1b3RllE6MDW1pc3NpbmdfcXVvdGWUTowOZG9pX3JlZ2lzdGVyZWSUTowIbWV0YWRhdGGUTowUbWV0YWRhdGFfZGlmZmVyZW5jZXOUXZSMCnJlZ2lzdGVyZWSUTowQdW5jaGVja2VkX3JlYXNvbpROjARoaW50lIw7TGVueiBjb3VsZCBub3QgcmVhY2ggdGhpcyBzb3VyY2UganVzdCBub3cuIFRyeSBhZ2FpbiBsYXRlci6UjAdmYWlsdXJllGgAjAxGYWlsdXJlQmxvY2uUk5QpgZR9lChoBX2UKIwOZmFpbHVyZV9yZWFzb26UjBR1cHN0cmVhbV91bmF2YWlsYWJsZZSMDWZhaWx1cmVfY2xhc3OUjBR1cHN0cmVhbV91bmF2YWlsYWJsZZSMCXJldHJ5YWJsZZSIaGmMO0xlbnogY291bGQgbm90IHJlYWNoIHRoaXMgc291cmNlIGp1c3Qgbm93LiBUcnkgYWdhaW4gbGF0ZXIulIwIZG9jc191cmyUjDBodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjdXBzdHJlYW0tdW5hdmFpbGFibGWUdWgZfZRoG4+UKGhpaHFod2hzaHWQaB1OdWJ1aBl9lGgbj5QoaFpoaGhgaFtoXGhpaGNoZGgJaGJoZWhhaFloZ2heaFhoXWhfaGuQaB1OdWJ1aBl9lGgbj5QoaExoUGhHaFFoRmhLaE1oSWhPkGgdTnViaEIpgZR9lChoBX2UKGhGSwFoR4wLYSBzdGF0ZW1lbnSUaEmMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGhLTmhMTmhNXZRoT05oUE5oUWhTKYGUfZQoaAV9lChoCYwGZmFpbGVklGhYTmhZTmhaTmhbTmhcTmhdTmheTmhfTmhgTmhhTmhiTmhjTmhkTmhlXZRoZ05oaE5oaYw7TGVueiBjb3VsZCBub3QgcmVhY2ggdGhpcyBzb3VyY2UganVzdCBub3cuIFRyeSBhZ2FpbiBsYXRlci6UaGtobSmBlH2UKGgFfZQoaHGMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGhzjBR1cHN0cmVhbV91bmF2YWlsYWJsZZRodYhoaYw7TGVueiBjb3VsZCBub3QgcmVhY2ggdGhpcyBzb3VyY2UganVzdCBub3cuIFRyeSBhZ2FpbiBsYXRlci6UaHeMMGh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyN1cHN0cmVhbS11bmF2YWlsYWJsZZR1aBl9lGgbj5QoaGlocWh3aHNodZBoHU51YnVoGX2UaBuPlChoWmhoaGBoW2hcaGloY2hkaAloYmhlaGFoWWhnaF5oWGhdaF9oa5BoHU51YnVoGX2UaBuPlChoTGhQaEdoUWhGaEtoTWhJaE+QaB1OdWJlaDNdlIwRY2l0YXRpb25fZmFpbHVyZXOUXZQoaACMFVJldmlld0NpdGF0aW9uRmFpbHVyZZSTlCmBlH2UKGgFfZQojA5jaXRhdGlvbl9pbmRleJRLAGhHjBphIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeZRoSYwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJRoS05oa2htKYGUfZQoaAV9lChocYwUdXBzdHJlYW1fdW5hdmFpbGFibGWUaHOMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGh1iGhpjDtMZW56IGNvdWxkIG5vdCByZWFjaCB0aGlzIHNvdXJjZSBqdXN0IG5vdy4gVHJ5IGFnYWluIGxhdGVyLpRod4wwaHR0cHM6Ly9sZW56LmlvL2RvY3MvZXJyb3JzI3Vwc3RyZWFtLXVuYXZhaWxhYmxllHVoGX2UaBuPlChoaWhxaHdoc2h1kGgdTnVidWgZfZRoG4+UKGhHaEtooGhJaGuQaB1OdWJonCmBlH2UKGgFfZQoaKBLAWhHjAthIHN0YXRlbWVudJRoSYwdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaEtOaGtobSmBlH2UKGgFfZQoaHGMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGhzjBR1cHN0cmVhbV91bmF2YWlsYWJsZZRodYhoaYw7TGVueiBjb3VsZCBub3QgcmVhY2ggdGhpcyBzb3VyY2UganVzdCBub3cuIFRyeSBhZ2FpbiBsYXRlci6UaHeMMGh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyN1cHN0cmVhbS11bmF2YWlsYWJsZZR1aBl9lGgbj5QoaGlocWh3aHNodZBoHU51YnVoGX2UaBuPlChoR2hLaKBoSWhrkGgdTnViZYwObW9yZV9jaXRhdGlvbnOUXZRoa2htKYGUfZQoaAV9lChocYwUdXBzdHJlYW1fdW5hdmFpbGFibGWUaHOMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGh1iGhpTmh3jDBodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjdXBzdHJlYW0tdW5hdmFpbGFibGWUdWgZfZRoG4+UKGhpaHFod2hzaHWQaB1OdWJ1aBl9lIwIbGFuZ3VhZ2WUjAJlbpRzaBuPlChoC2g2aA9oDWjJaAloEmg/aDNomWgRaAdoHmi+aGuQaB1OdWIu", + "citecheck__get_queued.json": "gASVtgUAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwGcXVldWVklIwHb3V0Y29tZZROjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5RLCowGcG9saWN5lGgAjA9DaXRlY2hlY2tQb2xpY3mUk5QpgZR9lChoBX2UjA1tYXhfY2l0YXRpb25zlEsBc4wSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoFpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwQQ2l0ZWNoZWNrU3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jaXRhdGlvbnNfZm91bmSUSwGMEmNpdGF0aW9uc19zZWxlY3RlZJRLAYwOY2l0YXRpb25fbGltaXSUSwGMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwCMCXVuY2hlY2tlZJRLAIwGZmFpbGVklEsAdWgXfZRoGY+UKGgsaC1oLpBoG051YowPY2l0YXRpb25faXNzdWVzlEsAdWgXfZRoGY+UKGgjaCVoMWgkaCZoIpBoG051YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwBzaBd9lGgZj5QoaDqQaBtOdWKMCWNpdGF0aW9uc5RdlGgAjA5SZXZpZXdDaXRhdGlvbpSTlCmBlH2UKGgFfZQojAVpbmRleJRLAIwJcmVmZXJlbmNllIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMCWNpdGVkX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjANkb2mUTowJc3RhdGVtZW50lIwiVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LpSMBnF1b3Rlc5RdlIwIcG9zaXRpb26UTowGcmVzdWx0lE6MBWNoZWNrlGgAjBNSZXZpZXdDaXRhdGlvbkNoZWNrlJOUKYGUfZQoaAV9lChoCYwHcGVuZGluZ5SMCXBhZ2VfcmVhZJROjApwYWdlX3RpdGxllE6ME3BhZ2VfcHVibGlzaGVkX2RhdGWUTowNcGFnZV9sYW5ndWFnZZROjApzb3VyY2VfdXJslE6MDnNvdXJjZV92ZXJzaW9ulE6MB3N1cHBvcnSUTowHc25pcHBldJROjAlyYXRpb25hbGWUTowFcXVvdGWUTowNbWlzc2luZ19xdW90ZZROjA5kb2lfcmVnaXN0ZXJlZJROjAhtZXRhZGF0YZROjBRtZXRhZGF0YV9kaWZmZXJlbmNlc5RdlIwKcmVnaXN0ZXJlZJROjBB1bmNoZWNrZWRfcmVhc29ulE6MBGhpbnSUTowHZmFpbHVyZZROdWgXfZRoGY+UKGhZaGdoX2haaFtoaGhiaGNoCWhhaGRoYGhYaGZoXWhXaFxoXmhpkGgbTnVidWgXfZRoGY+UKGhKaE9oRWhQaERoSWhMaEdoTpBoG051YmFoMV2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRoaU51aBd9lIwIbGFuZ3VhZ2WUjAJlbpRzaBmPlChoC2g0aA5oDGh0aAloEGg9aDFob2gPaAdoHGhxaGmQaBtOdWIu", + "citecheck__get_text_limit_exactly_at_limit.json": "gASVWQkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROjAZwb2xpY3mUaACMD0NpdGVjaGVja1BvbGljeZSTlCmBlH2UKGgFfZSMDW1heF9jaXRhdGlvbnOUSwJzjBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgYkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjBBDaXRlY2hlY2tTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NpdGF0aW9uc19mb3VuZJRLAowSY2l0YXRpb25zX3NlbGVjdGVklEsCjA5jaXRhdGlvbl9saW1pdJRLAowWY2l0YXRpb25fbGltaXRfcmVhY2hlZJSJjA9jaXRhdGlvbl9jaGVja3OUaACMGVJldmlld0NpdGF0aW9uQ2hlY2tDb3VudHOUk5QpgZR9lChoBX2UKIwHY2hlY2tlZJRLAowJdW5jaGVja2VklEsAjAZmYWlsZWSUSwB1aBl9lGgbj5QoaC5oL2gwkGgdTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwB1aBl9lGgbj5QoaCVoJ2gzaCZoKGgkkGgdTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoGX2UaBuPlChoPJBoHU51YowJY2l0YXRpb25zlF2UKGgAjA5SZXZpZXdDaXRhdGlvbpSTlCmBlH2UKGgFfZQojAVpbmRleJRLAIwJcmVmZXJlbmNllIwaYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnmUjAljaXRlZF91cmyUjB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwDZG9plE6MCXN0YXRlbWVudJSMS1VuZW1wbG95bWVudCBmZWxsIHRvIDQuMSUgaW4gMjAyNCwgYWNjb3JkaW5nIHRvIGEgcmVwb3J0IGZyb20gdGhlIG1pbmlzdHJ5LpSMBnF1b3Rlc5RdlIwIcG9zaXRpb26UaACMCFBvc2l0aW9ulJOUKYGUfZQoaAV9lCiMBXN0YXJ0lEsAjANlbmSUS26MBHRleHSUTnVoGX2UaBuPlChoVmhXaFiQaB1OdWKMBnJlc3VsdJRoAIwUUmV2aWV3Q2l0YXRpb25SZXN1bHSUk5QpgZR9lChoBX2UKIwHZmluZGluZ5SMCXN1cHBvcnRlZJSMBnNvdXJjZZSMB3N1cHBvcnSUjAhpc19pc3N1ZZSJdWgZfZRoG4+UKGhhaGVoY5BoHU51YowFY2hlY2uUaACME1Jldmlld0NpdGF0aW9uQ2hlY2uUk5QpgZR9lChoBX2UKGgJjAljb21wbGV0ZWSUjAlwYWdlX3JlYWSUjARmdWxslIwKcGFnZV90aXRsZZSMJ1BhZ2UgYXQgaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSME3BhZ2VfcHVibGlzaGVkX2RhdGWUTowNcGFnZV9sYW5ndWFnZZSMAmVulIwKc291cmNlX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjA5zb3VyY2VfdmVyc2lvbpROjAdzdXBwb3J0lIwJc3VwcG9ydGVklIwHc25pcHBldJSME1RoZSBzb3VyY2Ugc2F5cyBzby6UjAlyYXRpb25hbGWUjBNUaGUgcGFnZSBzdGF0ZXMgaXQulIwFcXVvdGWUTowNbWlzc2luZ19xdW90ZZROjA5kb2lfcmVnaXN0ZXJlZJROjAhtZXRhZGF0YZROjBRtZXRhZGF0YV9kaWZmZXJlbmNlc5RdlIwKcmVnaXN0ZXJlZJROjBB1bmNoZWNrZWRfcmVhc29ulE6MBGhpbnSUTowHZmFpbHVyZZROdWgZfZRoG4+UKGhzaIZofWh0aHZoh2iBaIJoCWiAaINof2hxaIVoeWhvaHhoe2iIkGgdTnVidWgZfZRoG4+UKGhMaFtoR2hoaEZoS2hOaEloUJBoHU51YmhCKYGUfZQoaAV9lChoRksBaEeMC2Egc3RhdGVtZW50lGhJjB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRoS05oTIwiVGhlIGFnZW5jeSBzYWlkIHNvIGluIGEgc3RhdGVtZW50LpRoTl2UaFBoUimBlH2UKGgFfZQoaFZLb2hXS7JoWE51aBl9lGgbj5QoaFZoV2hYkGgdTnViaFtoXSmBlH2UKGgFfZQoaGGMCXN1cHBvcnRlZJRoY4wHc3VwcG9ydJRoZYl1aBl9lGgbj5QoaGFoZWhjkGgdTnViaGhoaimBlH2UKGgFfZQoaAmMCWNvbXBsZXRlZJRob4wEZnVsbJRocYwlUGFnZSBhdCBodHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRoc05odIwCZW6UaHaMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGh4Tmh5jAlzdXBwb3J0ZWSUaHuME1RoZSBzb3VyY2Ugc2F5cyBzby6UaH2ME1RoZSBwYWdlIHN0YXRlcyBpdC6UaH9OaIBOaIFOaIJOaINdlGiFTmiGTmiHTmiITnVoGX2UaBuPlChoc2iGaH1odGh2aIdogWiCaAlogGiDaH9ocWiFaHlob2h4aHtoiJBoHU51YnVoGX2UaBuPlChoTGhbaEdoaGhGaEtoTmhJaFCQaB1OdWJlaDNdlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMDm1vcmVfY2l0YXRpb25zlF2UaIhOdWgZfZSMCGxhbmd1YWdllIwCZW6Uc2gbj5QoaAtoNmgPaA1otmgJaBJoP2gzaLFoEWgHaB5os2iIkGgdTnViLg==", + "citecheck__get_text_limit_reached.json": "gASVHggAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwJQ2l0ZWNoZWNrlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMDGNpdGVjaGVja19pZJSMCDhlYjQ5MzAylIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROjAZwb2xpY3mUaACMD0NpdGVjaGVja1BvbGljeZSTlCmBlH2UKGgFfZSMDW1heF9jaXRhdGlvbnOUSwFzjBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgYkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjBBDaXRlY2hlY2tTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NpdGF0aW9uc19mb3VuZJRLAowSY2l0YXRpb25zX3NlbGVjdGVklEsBjA5jaXRhdGlvbl9saW1pdJRLAYwWY2l0YXRpb25fbGltaXRfcmVhY2hlZJSIjA9jaXRhdGlvbl9jaGVja3OUaACMGVJldmlld0NpdGF0aW9uQ2hlY2tDb3VudHOUk5QpgZR9lChoBX2UKIwHY2hlY2tlZJRLAYwJdW5jaGVja2VklEsAjAZmYWlsZWSUSwB1aBl9lGgbj5QoaC5oL2gwkGgdTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwB1aBl9lGgbj5QoaCVoJ2gzaCZoKGgkkGgdTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAXNoGX2UaBuPlChoPJBoHU51YowJY2l0YXRpb25zlF2UaACMDlJldmlld0NpdGF0aW9ulJOUKYGUfZQoaAV9lCiMBWluZGV4lEsAjAlyZWZlcmVuY2WUjBphIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeZSMCWNpdGVkX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjANkb2mUTowJc3RhdGVtZW50lIxLVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LCBhY2NvcmRpbmcgdG8gYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnkulIwGcXVvdGVzlF2UjAhwb3NpdGlvbpRoAIwIUG9zaXRpb26Uk5QpgZR9lChoBX2UKIwFc3RhcnSUSwCMA2VuZJRLbowEdGV4dJROdWgZfZRoG4+UKGhWaFdoWJBoHU51YowGcmVzdWx0lGgAjBRSZXZpZXdDaXRhdGlvblJlc3VsdJSTlCmBlH2UKGgFfZQojAdmaW5kaW5nlIwJc3VwcG9ydGVklIwGc291cmNllIwHc3VwcG9ydJSMCGlzX2lzc3VllIl1aBl9lGgbj5QoaGFoZWhjkGgdTnVijAVjaGVja5RoAIwTUmV2aWV3Q2l0YXRpb25DaGVja5STlCmBlH2UKGgFfZQoaAmMCWNvbXBsZXRlZJSMCXBhZ2VfcmVhZJSMBGZ1bGyUjApwYWdlX3RpdGxllIwnUGFnZSBhdCBodHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwTcGFnZV9wdWJsaXNoZWRfZGF0ZZROjA1wYWdlX2xhbmd1YWdllIwCZW6UjApzb3VyY2VfdXJslIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMDnNvdXJjZV92ZXJzaW9ulE6MB3N1cHBvcnSUjAlzdXBwb3J0ZWSUjAdzbmlwcGV0lIwTVGhlIHNvdXJjZSBzYXlzIHNvLpSMCXJhdGlvbmFsZZSME1RoZSBwYWdlIHN0YXRlcyBpdC6UjAVxdW90ZZROjA1taXNzaW5nX3F1b3RllE6MDmRvaV9yZWdpc3RlcmVklE6MCG1ldGFkYXRhlE6MFG1ldGFkYXRhX2RpZmZlcmVuY2VzlF2UjApyZWdpc3RlcmVklE6MEHVuY2hlY2tlZF9yZWFzb26UTowEaGludJROjAdmYWlsdXJllE51aBl9lGgbj5QoaHNohmh9aHRodmiHaIFogmgJaIBog2h/aHFohWh5aG9oeGh7aIiQaB1OdWJ1aBl9lGgbj5QoaExoW2hHaGhoRmhLaE5oSWhQkGgdTnViYWgzXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjA5tb3JlX2NpdGF0aW9uc5RdlGgAjBJSZXZpZXdNb3JlQ2l0YXRpb26Uk5QpgZR9lChoBX2UKGhGSwFoR4wLYSBzdGF0ZW1lbnSUaEmMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGhLTowIc2VudGVuY2WUjCJUaGUgYWdlbmN5IHNhaWQgc28gaW4gYSBzdGF0ZW1lbnQulGhQaFIpgZR9lChoBX2UKGhWS29oV0uyaFhOdWgZfZRoG4+UKGhWaFdoWJBoHU51YnVoGX2UaBuPlChoR2iZaEZoS2hJaFCQaB1OdWJhaIhOdWgZfZSMCGxhbmd1YWdllIwCZW6Uc2gbj5QoaAtoNmgPaA1oo2gJaBJoP2gzaI5oEWgHaB5okGiIkGgdTnViLg==", + "citecheck__idempotent_replay_202.json": "gASVuwAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwQQ2l0ZWNoZWNrU3RhcnRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAxjaXRlY2hlY2tfaWSUjAg4ZWI0OTMwMpSMBnN0YXR1c5SMBnF1ZXVlZJR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgHaAmQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "citecheck__receipt_202.json": "gASVuwAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwQQ2l0ZWNoZWNrU3RhcnRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAxjaXRlY2hlY2tfaWSUjAg4ZWI0OTMwMpSMBnN0YXR1c5SMBnF1ZXVlZJR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgHaAmQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "citecheck__receipt_202_empty_webhook_url.json": "gASVuwAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwQQ2l0ZWNoZWNrU3RhcnRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAxjaXRlY2hlY2tfaWSUjAg4ZWI0OTMwMpSMBnN0YXR1c5SMBnF1ZXVlZJR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgHaAmQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "extract__focus_ready.json": "gASVMgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMBXJlYWR5lIwFY2xhaW2UjBdCZXRhIGZlbGwgMyUgbGFzdCB5ZWFyLpSMEWlkZW50aWZpZWRfY2xhaW1zlF2UjBBjYW5kaWRhdGVfY2xhaW1zlF2UjAZkb21haW6UjAlFY29ub21pY3OUjAxrZXlfZW50aXRpZXOUXZQoaACMD0V4dHJhY3RlZEVudGl0eZSTlCmBlH2UKGgFfZQojARuYW1llIwFQWxwaGGUjAR0eXBllIwMb3JnYW5pemF0aW9ulHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBhoGpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmgUKYGUfZQoaAV9lChoGIwEQmV0YZRoGowMb3JnYW5pemF0aW9ulHVoHH2UaB6PlChoGGgakGggTnViZYwPcHJlc3VtZWRfaW50ZW50lIwXVmVyaWZ5IHJlcG9ydGVkIGZpZ3VyZXOUjA5vcmlnaW5hbF9pbnB1dJSMLkFscGhhIHJvc2UgNSUgaW4gMjAyNC4gQmV0YSBmZWxsIDMlIGxhc3QgeWVhci6UjAlsb2NhdGlvbnOUTnVoHH2UaB6PlChoEWgJaA1oC2gHaA9oLGgqaCiQaCBOdWIu", + "extract__idempotency_replay.json": "gASVZgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMBXJlYWR5lIwFY2xhaW2UjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwRaWRlbnRpZmllZF9jbGFpbXOUXZQojBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwXQmV0YSBmZWxsIDMlIGxhc3QgeWVhci6UZYwQY2FuZGlkYXRlX2NsYWltc5RdlIwGZG9tYWlulIwJRWNvbm9taWNzlIwMa2V5X2VudGl0aWVzlF2UKGgAjA9FeHRyYWN0ZWRFbnRpdHmUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUFscGhhlIwEdHlwZZSMDG9yZ2FuaXphdGlvbpR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgaaByQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJoFimBlH2UKGgFfZQoaBqMBEJldGGUaByMDG9yZ2FuaXphdGlvbpR1aB59lGggj5QoaBpoHJBoIk51YmWMD3ByZXN1bWVkX2ludGVudJSMF1ZlcmlmeSByZXBvcnRlZCBmaWd1cmVzlIwOb3JpZ2luYWxfaW5wdXSUjC5BbHBoYSByb3NlIDUlIGluIDIwMjQuIEJldGEgZmVsbCAzJSBsYXN0IHllYXIulIwJbG9jYXRpb25zlE51aB59lGggj5QoaBNoCWgPaAtoB2gRaC5oLGgqkGgiTnViLg==", + "extract__locate_all_dropped.json": "gASVGAIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMC25vdF9hX2NsYWltlIwFY2xhaW2UjACUjBFpZGVudGlmaWVkX2NsYWltc5RdlIwQY2FuZGlkYXRlX2NsYWltc5RdlIwGZG9tYWlulGgKjAxrZXlfZW50aXRpZXOUXZQoaACMD0V4dHJhY3RlZEVudGl0eZSTlCmBlH2UKGgFfZQojARuYW1llIwFQWxwaGGUjAR0eXBllIwMb3JnYW5pemF0aW9ulHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBdoGZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmgTKYGUfZQoaAV9lChoF4wEQmV0YZRoGYwMb3JnYW5pemF0aW9ulHVoG32UaB2PlChoF2gZkGgfTnViZYwPcHJlc3VtZWRfaW50ZW50lIwXVmVyaWZ5IHJlcG9ydGVkIGZpZ3VyZXOUjA5vcmlnaW5hbF9pbnB1dJSMLkFscGhhIHJvc2UgNSUgaW4gMjAyNC4gQmV0YSBmZWxsIDMlIGxhc3QgeWVhci6UjAlsb2NhdGlvbnOUXZR1aBt9lGgdj5QoaBBoCWgNaAtoB2gPaCtoKWgnkGgfTnViLg==", + "extract__locate_failed.json": "gASVZgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMBXJlYWR5lIwFY2xhaW2UjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwRaWRlbnRpZmllZF9jbGFpbXOUXZQojBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwXQmV0YSBmZWxsIDMlIGxhc3QgeWVhci6UZYwQY2FuZGlkYXRlX2NsYWltc5RdlIwGZG9tYWlulIwJRWNvbm9taWNzlIwMa2V5X2VudGl0aWVzlF2UKGgAjA9FeHRyYWN0ZWRFbnRpdHmUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUFscGhhlIwEdHlwZZSMDG9yZ2FuaXphdGlvbpR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgaaByQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJoFimBlH2UKGgFfZQoaBqMBEJldGGUaByMDG9yZ2FuaXphdGlvbpR1aB59lGggj5QoaBpoHJBoIk51YmWMD3ByZXN1bWVkX2ludGVudJSMF1ZlcmlmeSByZXBvcnRlZCBmaWd1cmVzlIwOb3JpZ2luYWxfaW5wdXSUjC5BbHBoYSByb3NlIDUlIGluIDIwMjQuIEJldGEgZmVsbCAzJSBsYXN0IHllYXIulIwJbG9jYXRpb25zlE51aB59lGggj5QoaBNoCWgPaAtoB2gRaC5oLGgqkGgiTnViLg==", + "extract__locate_leading_whitespace.json": "gASV8gIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMBXJlYWR5lIwFY2xhaW2UjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwRaWRlbnRpZmllZF9jbGFpbXOUXZSMEGNhbmRpZGF0ZV9jbGFpbXOUXZSMBmRvbWFpbpSMCUVjb25vbWljc5SMDGtleV9lbnRpdGllc5RdlChoAIwPRXh0cmFjdGVkRW50aXR5lJOUKYGUfZQoaAV9lCiMBG5hbWWUjAVBbHBoYZSMBHR5cGWUjAxvcmdhbml6YXRpb26UdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGGgakIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViaBQpgZR9lChoBX2UKGgYjARCZXRhlGgajAxvcmdhbml6YXRpb26UdWgcfZRoHo+UKGgYaBqQaCBOdWJljA9wcmVzdW1lZF9pbnRlbnSUjBdWZXJpZnkgcmVwb3J0ZWQgZmlndXJlc5SMDm9yaWdpbmFsX2lucHV0lIwuQWxwaGEgcm9zZSA1JSBpbiAyMDI0LiBCZXRhIGZlbGwgMyUgbGFzdCB5ZWFyLpSMCWxvY2F0aW9uc5RdlGgAjA1DbGFpbUxvY2F0aW9ulJOUKYGUfZQoaAV9lChoCYwWQWxwaGEgcm9zZSA1JSBpbiAyMDI0LpSMCXBvc2l0aW9uc5RdlGgAjAhQb3NpdGlvbpSTlCmBlH2UKGgFfZQojAVzdGFydJRLA4wDZW5klEsZjAR0ZXh0lIwWQWxwaGEgcm9zZSA1JSBpbiAyMDI0LpR1aBx9lGgej5QoaDtoPGg9kGggTnViYXVoHH2UaB6PlChoCWg0kGggTnViYXVoHH2UaB6PlChoEWgJaA1oC2gHaA9oLGgqaCiQaCBOdWIu", + "extract__locate_some_dropped.json": "gASVsQMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMBXJlYWR5lIwFY2xhaW2UjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwRaWRlbnRpZmllZF9jbGFpbXOUXZQojBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwXQmV0YSBmZWxsIDMlIGxhc3QgeWVhci6UZYwQY2FuZGlkYXRlX2NsYWltc5RdlIwGZG9tYWlulIwJRWNvbm9taWNzlIwMa2V5X2VudGl0aWVzlF2UKGgAjA9FeHRyYWN0ZWRFbnRpdHmUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUFscGhhlIwEdHlwZZSMDG9yZ2FuaXphdGlvbpR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgaaByQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJoFimBlH2UKGgFfZQoaBqMBEJldGGUaByMDG9yZ2FuaXphdGlvbpR1aB59lGggj5QoaBpoHJBoIk51YmWMD3ByZXN1bWVkX2ludGVudJSMF1ZlcmlmeSByZXBvcnRlZCBmaWd1cmVzlIwOb3JpZ2luYWxfaW5wdXSUjC5BbHBoYSByb3NlIDUlIGluIDIwMjQuIEJldGEgZmVsbCAzJSBsYXN0IHllYXIulIwJbG9jYXRpb25zlF2UKGgAjA1DbGFpbUxvY2F0aW9ulJOUKYGUfZQoaAV9lChoCYwWQWxwaGEgcm9zZSA1JSBpbiAyMDI0LpSMCXBvc2l0aW9uc5RdlGgAjAhQb3NpdGlvbpSTlCmBlH2UKGgFfZQojAVzdGFydJRLAIwDZW5klEsWjAR0ZXh0lIwWQWxwaGEgcm9zZSA1JSBpbiAyMDI0LpR1aB59lGggj5QoaD1oPmg/kGgiTnViYXVoHn2UaCCPlChoCWg2kGgiTnViaDEpgZR9lChoBX2UKGgJjBdCZXRhIGZlbGwgMyUgbGFzdCB5ZWFyLpRoNl2UaDkpgZR9lChoBX2UKGg9SxdoPksuaD+MF0JldGEgZmVsbCAzJSBsYXN0IHllYXIulHVoHn2UaCCPlChoPWg+aD+QaCJOdWJhdWgefZRoII+UKGgJaDaQaCJOdWJldWgefZRoII+UKGgTaAloD2gLaAdoEWguaCxoKpBoIk51Yi4=", + "extract__locate_true.json": "gASVsQMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMBXJlYWR5lIwFY2xhaW2UjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwRaWRlbnRpZmllZF9jbGFpbXOUXZQojBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwXQmV0YSBmZWxsIDMlIGxhc3QgeWVhci6UZYwQY2FuZGlkYXRlX2NsYWltc5RdlIwGZG9tYWlulIwJRWNvbm9taWNzlIwMa2V5X2VudGl0aWVzlF2UKGgAjA9FeHRyYWN0ZWRFbnRpdHmUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUFscGhhlIwEdHlwZZSMDG9yZ2FuaXphdGlvbpR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgaaByQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJoFimBlH2UKGgFfZQoaBqMBEJldGGUaByMDG9yZ2FuaXphdGlvbpR1aB59lGggj5QoaBpoHJBoIk51YmWMD3ByZXN1bWVkX2ludGVudJSMF1ZlcmlmeSByZXBvcnRlZCBmaWd1cmVzlIwOb3JpZ2luYWxfaW5wdXSUjC5BbHBoYSByb3NlIDUlIGluIDIwMjQuIEJldGEgZmVsbCAzJSBsYXN0IHllYXIulIwJbG9jYXRpb25zlF2UKGgAjA1DbGFpbUxvY2F0aW9ulJOUKYGUfZQoaAV9lChoCYwWQWxwaGEgcm9zZSA1JSBpbiAyMDI0LpSMCXBvc2l0aW9uc5RdlGgAjAhQb3NpdGlvbpSTlCmBlH2UKGgFfZQojAVzdGFydJRLAIwDZW5klEsWjAR0ZXh0lIwWQWxwaGEgcm9zZSA1JSBpbiAyMDI0LpR1aB59lGggj5QoaD1oPmg/kGgiTnViYXVoHn2UaCCPlChoCWg2kGgiTnViaDEpgZR9lChoBX2UKGgJjBdCZXRhIGZlbGwgMyUgbGFzdCB5ZWFyLpRoNl2UaDkpgZR9lChoBX2UKGg9SxdoPksuaD+MF0JldGEgZmVsbCAzJSBsYXN0IHllYXIulHVoHn2UaCCPlChoPWg+aD+QaCJOdWJhdWgefZRoII+UKGgJaDaQaCJOdWJldWgefZRoII+UKGgTaAloD2gLaAdoEWguaCxoKpBoIk51Yi4=", + "extract__no_match_with_focus.json": "gASVZQEAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMCG5vX21hdGNolIwFY2xhaW2UjACUjBFpZGVudGlmaWVkX2NsYWltc5RdlIwQY2FuZGlkYXRlX2NsYWltc5RdlIwGZG9tYWlulGgKjAxrZXlfZW50aXRpZXOUXZSMD3ByZXN1bWVkX2ludGVudJRoCowOb3JpZ2luYWxfaW5wdXSUjC5BbHBoYSByb3NlIDUlIGluIDIwMjQuIEJldGEgZmVsbCAzJSBsYXN0IHllYXIulIwJbG9jYXRpb25zlE51jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgQaAloDWgLaAdoD2gVaBNoEpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51Yi4=", + "extract__not_a_claim.json": "gASVTAEAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMC25vdF9hX2NsYWltlIwFY2xhaW2UjACUjBFpZGVudGlmaWVkX2NsYWltc5RdlIwQY2FuZGlkYXRlX2NsYWltc5RdlIwGZG9tYWlulGgKjAxrZXlfZW50aXRpZXOUXZSMD3ByZXN1bWVkX2ludGVudJRoCowOb3JpZ2luYWxfaW5wdXSUjBJXaGF0IGEgbG92ZWx5IGRheS6UjAlsb2NhdGlvbnOUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBBoCWgNaAtoB2gPaBVoE2gSkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViLg==", + "extract__not_a_claim_beside_claims.json": "gASVHwIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMC25vdF9hX2NsYWltlIwFY2xhaW2UjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwRaWRlbnRpZmllZF9jbGFpbXOUXZSMEGNhbmRpZGF0ZV9jbGFpbXOUXZSMBmRvbWFpbpSMCUVjb25vbWljc5SMDGtleV9lbnRpdGllc5RdlChoAIwPRXh0cmFjdGVkRW50aXR5lJOUKYGUfZQoaAV9lCiMBG5hbWWUjAVBbHBoYZSMBHR5cGWUjAxvcmdhbml6YXRpb26UdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGGgakIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViaBQpgZR9lChoBX2UKGgYjARCZXRhlGgajAxvcmdhbml6YXRpb26UdWgcfZRoHo+UKGgYaBqQaCBOdWJljA9wcmVzdW1lZF9pbnRlbnSUjBdWZXJpZnkgcmVwb3J0ZWQgZmlndXJlc5SMDm9yaWdpbmFsX2lucHV0lIwWQWxwaGEgcm9zZSA1JSBpbiAyMDI0LpSMCWxvY2F0aW9uc5ROdWgcfZRoHo+UKGgRaAloDWgLaAdoD2gsaCpoKJBoIE51Yi4=", + "extract__ready_one_claim.json": "gASVGQIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMBXJlYWR5lIwFY2xhaW2UjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwRaWRlbnRpZmllZF9jbGFpbXOUXZSMEGNhbmRpZGF0ZV9jbGFpbXOUXZSMBmRvbWFpbpSMCUVjb25vbWljc5SMDGtleV9lbnRpdGllc5RdlChoAIwPRXh0cmFjdGVkRW50aXR5lJOUKYGUfZQoaAV9lCiMBG5hbWWUjAVBbHBoYZSMBHR5cGWUjAxvcmdhbml6YXRpb26UdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGGgakIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViaBQpgZR9lChoBX2UKGgYjARCZXRhlGgajAxvcmdhbml6YXRpb26UdWgcfZRoHo+UKGgYaBqQaCBOdWJljA9wcmVzdW1lZF9pbnRlbnSUjBdWZXJpZnkgcmVwb3J0ZWQgZmlndXJlc5SMDm9yaWdpbmFsX2lucHV0lIwWQWxwaGEgcm9zZSA1JSBpbiAyMDI0LpSMCWxvY2F0aW9uc5ROdWgcfZRoHo+UKGgRaAloDWgLaAdoD2gsaCpoKJBoIE51Yi4=", + "extract__ready_several_claims.json": "gASVZgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMBXJlYWR5lIwFY2xhaW2UjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwRaWRlbnRpZmllZF9jbGFpbXOUXZQojBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwXQmV0YSBmZWxsIDMlIGxhc3QgeWVhci6UZYwQY2FuZGlkYXRlX2NsYWltc5RdlIwGZG9tYWlulIwJRWNvbm9taWNzlIwMa2V5X2VudGl0aWVzlF2UKGgAjA9FeHRyYWN0ZWRFbnRpdHmUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUFscGhhlIwEdHlwZZSMDG9yZ2FuaXphdGlvbpR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgaaByQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJoFimBlH2UKGgFfZQoaBqMBEJldGGUaByMDG9yZ2FuaXphdGlvbpR1aB59lGggj5QoaBpoHJBoIk51YmWMD3ByZXN1bWVkX2ludGVudJSMF1ZlcmlmeSByZXBvcnRlZCBmaWd1cmVzlIwOb3JpZ2luYWxfaW5wdXSUjC5BbHBoYSByb3NlIDUlIGluIDIwMjQuIEJldGEgZmVsbCAzJSBsYXN0IHllYXIulIwJbG9jYXRpb25zlE51aB59lGggj5QoaBNoCWgPaAtoB2gRaC5oLGgqkGgiTnViLg==", + "extract__replay_later_200.json": "gASVZgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMBXJlYWR5lIwFY2xhaW2UjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwRaWRlbnRpZmllZF9jbGFpbXOUXZQojBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwXQmV0YSBmZWxsIDMlIGxhc3QgeWVhci6UZYwQY2FuZGlkYXRlX2NsYWltc5RdlIwGZG9tYWlulIwJRWNvbm9taWNzlIwMa2V5X2VudGl0aWVzlF2UKGgAjA9FeHRyYWN0ZWRFbnRpdHmUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUFscGhhlIwEdHlwZZSMDG9yZ2FuaXphdGlvbpR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgaaByQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJoFimBlH2UKGgFfZQoaBqMBEJldGGUaByMDG9yZ2FuaXphdGlvbpR1aB59lGggj5QoaBpoHJBoIk51YmWMD3ByZXN1bWVkX2ludGVudJSMF1ZlcmlmeSByZXBvcnRlZCBmaWd1cmVzlIwOb3JpZ2luYWxfaW5wdXSUjC5BbHBoYSByb3NlIDUlIGluIDIwMjQuIEJldGEgZmVsbCAzJSBsYXN0IHllYXIulIwJbG9jYXRpb25zlE51aB59lGggj5QoaBNoCWgPaAtoB2gRaC5oLGgqkGgiTnViLg==", + "extract__url_input_located.json": "gASV4AIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwPRXh0cmFjdGVkQ2xhaW1zlJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMBnN0YXR1c5SMBXJlYWR5lIwFY2xhaW2UjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwRaWRlbnRpZmllZF9jbGFpbXOUXZSMEGNhbmRpZGF0ZV9jbGFpbXOUXZSMBmRvbWFpbpSMCUVjb25vbWljc5SMDGtleV9lbnRpdGllc5RdlChoAIwPRXh0cmFjdGVkRW50aXR5lJOUKYGUfZQoaAV9lCiMBG5hbWWUjAVBbHBoYZSMBHR5cGWUjAxvcmdhbml6YXRpb26UdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGGgakIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViaBQpgZR9lChoBX2UKGgYjARCZXRhlGgajAxvcmdhbml6YXRpb26UdWgcfZRoHo+UKGgYaBqQaCBOdWJljA9wcmVzdW1lZF9pbnRlbnSUjBdWZXJpZnkgcmVwb3J0ZWQgZmlndXJlc5SMDm9yaWdpbmFsX2lucHV0lIweaHR0cHM6Ly9leGFtcGxlLmNvbS9hbi1hcnRpY2xllIwJbG9jYXRpb25zlF2UaACMDUNsYWltTG9jYXRpb26Uk5QpgZR9lChoBX2UKGgJjBZBbHBoYSByb3NlIDUlIGluIDIwMjQulIwJcG9zaXRpb25zlF2UaACMCFBvc2l0aW9ulJOUKYGUfZQoaAV9lCiMBXN0YXJ0lE6MA2VuZJROjAR0ZXh0lIwWQWxwaGEgcm9zZSA1JSBpbiAyMDI0LpR1aBx9lGgej5QoaDtoPGg9kGggTnViYXVoHH2UaB6PlChoCWg0kGggTnViYXVoHH2UaB6PlChoEWgJaA1oC2gHaA9oLGgqaCiQaCBOdWIu", + "review__get_assessing.json": "gASVTgcAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJYXNzZXNzaW5nlIwHb3V0Y29tZZROjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lIwbMjAyNi0xMC0wMVQxMDowNzowMC4xMjM0NTZalIwIbGFuZ3VhZ2WUjAJlbpSMBnBvbGljeZRoAIwQRXNjYWxhdGlvblBvbGljeZSTlCmBlH2UKGgFfZQojAh2ZXJkaWN0c5RdlCiMBUZhbHNllIwMTW9zdGx5IEZhbHNllIwFTWl4ZWSUZYwKY29uZmlkZW5jZZRdlIwDbG93lGGMD21heF9hc3Nlc3NtZW50c5RLFIwRbWF4X3ZlcmlmaWNhdGlvbnOUSwWMBWRlcHRolIwIc3RhbmRhcmSUjA1tYXhfY2l0YXRpb25zlEsAjA1zdWdnZXN0X2VkaXRzlIl1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgaaCRoH2gmaCdoI2gikIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjA1SZXZpZXdTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NsYWltc19zZWxlY3RlZJRLAowLY2xhaW1fbGltaXSUSxSME2NsYWltX2xpbWl0X3JlYWNoZWSUiYwPaW5wdXRfdHJ1bmNhdGVklImMC2Fzc2Vzc21lbnRzlGgAjBZSZXZpZXdBc3Nlc3NtZW50Q291bnRzlJOUKYGUfZQoaAV9lCiMCWNvbXBsZXRlZJRLAIwGZmFpbGVklEsAdWgofZRoKo+UKGg9aD6QaCxOdWKMDXZlcmlmaWNhdGlvbnOUTowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKH2UaCqPlChoM2g3aDZoRGhBaEloRmhCaDRoRWhIaEdoQ2g1kGgsTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoKH2UaCqPlChoUpBoLE51YowScG9sbF9hZnRlcl9zZWNvbmRzlEsKaEJdlIwIZmFpbHVyZXOUXZRoSF2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUXZSMFG1vcmVfY2xhaW1fbG9jYXRpb25zlF2UjA5tb3JlX2NpdGF0aW9uc5RdlIwHZmFpbHVyZZROjAZjbGFpbXOUXZQoaACMC1Jldmlld0NsYWltlJOUKYGUfZQoaAV9lCiMBWluZGV4lEsAjAVjbGFpbZSMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAlwb3NpdGlvbnOUTowGcmVzdWx0lE6MCmFzc2Vzc21lbnSUaACMEFJldmlld0Fzc2Vzc21lbnSUk5QpgZR9lChoBX2UKGgLjAdydW5uaW5nlIwHdmVyZGljdJROaB9OjAlyYXRpb25hbGWUTowHZGlzc2VudJROjBB2ZXJpZmljYXRpb25fdXJslE6MCmVycm9yX2NvZGWUTowRaWRlbnRpZmllZF9jbGFpbXOUXZSMBGhpbnSUTowRc3VnZ2VzdGVkX3Jld3JpdGWUTmhiTnVoKH2UaCqPlChofWh4aHloH2gLaHZoe2h3aHpofmhikGgsTnVijAplc2NhbGF0aW9ulE6MDHZlcmlmaWNhdGlvbpROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoKH2UaCqPlChoa2hvaIFoamiCaINobmhtkGgsTnViaGYpgZR9lChoBX2UKGhqSwFoa4wiV2F0ZXIgYm9pbHMgYXQgMTAwIEMgYXQgc2VhIGxldmVsLpRobU5obk5ob2hxKYGUfZQoaAV9lChoC4wHcnVubmluZ5Rodk5oH05od05oeE5oeU5oek5oe12UaH1OaH5OaGJOdWgofZRoKo+UKGh9aHhoeWgfaAtodmh7aHdoemh+aGKQaCxOdWJogU5ogk5og051aCh9lGgqj5QoaGtob2iBaGpogmiDaG5obZBoLE51YmWMCWNpdGF0aW9uc5RdlHVoKH2UaCqPlChoXGhXaBBoC2gUaFpoVWgtaGBoTGgOaEhoY2gNaF5oEmgJaJNoQmgHaGKQaCxOdWIu", + "review__get_assessment_rows_full_fields.json": "gASV+QwAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMCmluY29tcGxldGWUjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lIwbMjAyNi0xMC0wMVQxMDowNzowMC4xMjM0NTZalIwIbGFuZ3VhZ2WUjAJlbpSMBnBvbGljeZRoAIwQRXNjYWxhdGlvblBvbGljeZSTlCmBlH2UKGgFfZQojAh2ZXJkaWN0c5RdlCiMBUZhbHNllIwMTW9zdGx5IEZhbHNllIwFTWl4ZWSUZYwKY29uZmlkZW5jZZRdlIwDbG93lGGMD21heF9hc3Nlc3NtZW50c5RLFIwRbWF4X3ZlcmlmaWNhdGlvbnOUSwCMBWRlcHRolIwIc3RhbmRhcmSUjA1tYXhfY2l0YXRpb25zlEsAjA1zdWdnZXN0X2VkaXRzlIl1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgbaCVoIGgnaChoJGgjkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjA1SZXZpZXdTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NsYWltc19zZWxlY3RlZJRLAowLY2xhaW1fbGltaXSUSxSME2NsYWltX2xpbWl0X3JlYWNoZWSUiYwPaW5wdXRfdHJ1bmNhdGVklImMC2Fzc2Vzc21lbnRzlGgAjBZSZXZpZXdBc3Nlc3NtZW50Q291bnRzlJOUKYGUfZQoaAV9lCiMCWNvbXBsZXRlZJRLAYwGZmFpbGVklEsBdWgpfZRoK4+UKGg+aD+QaC1OdWKMDXZlcmlmaWNhdGlvbnOUaACMGFJldmlld1ZlcmlmaWNhdGlvbkNvdW50c5STlCmBlH2UKGgFfZQojAdwbGFubmVklEsAaD5LAGg/SwB1aCl9lGgrj5QoaD5oP2hIkGgtTnVijAZpc3N1ZXOUSwGMD2NpdGF0aW9uc19mb3VuZJROjBJjaXRhdGlvbnNfc2VsZWN0ZWSUTowOY2l0YXRpb25fbGltaXSUTowWY2l0YXRpb25fbGltaXRfcmVhY2hlZJROjA9jaXRhdGlvbl9jaGVja3OUTowPY2l0YXRpb25faXNzdWVzlEsAjBFjaXRhdGlvbnNfc2tpcHBlZJROdWgpfZRoK4+UKGg0aDhoN2hNaEJoUmhPaEtoNWhOaFFoUGhMaDaQaC1OdWKMB2NyZWRpdHOUaACMDVJldmlld0NyZWRpdHOUk5QpgZR9lChoBX2UjAdjaGFyZ2VklEsCc2gpfZRoK4+UKGhbkGgtTnVijBJwb2xsX2FmdGVyX3NlY29uZHOUTmhLXZRoAIwLUmV2aWV3SXNzdWWUk5QpgZR9lChoBX2UKIwLY2xhaW1faW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMDnZlcmlmaWVkX2NsYWltlE6MB3ZlcmRpY3SUjAVGYWxzZZRoIIwEaGlnaJSMBnNvdXJjZZSMCmFzc2Vzc21lbnSUjA92ZXJpZmljYXRpb25faWSUTowTdmVyaWZpY2F0aW9uX3N0YXR1c5ROjBB2ZXJpZmljYXRpb25fdXJslE6MA3VybJROjAplc2NhbGF0aW9ulGgAjApFc2NhbGF0aW9ulJOUKYGUfZQoaAV9lCiMDW1hdGNoZWRfcnVsZXOUXZSMB3ZlcmRpY3SUYYwLZGlzcG9zaXRpb26UjANjYXCUdWgpfZRoK4+UKGh7aHiQaC1OdWKMC2tleV9maW5kaW5nlE6MCXJhdGlvbmFsZZSMI1R3byByZXZpZXdlcnMgZm91bmQgdGhlIGRhdGUgd3JvbmculIwRc3VnZ2VzdGVkX3Jld3JpdGWUjDBUaGUgRVUgQUkgQWN0IGVudGVyZWQgaW50byBmb3JjZSBpbiBBdWd1c3QgMjAyNC6UjAdmYWlsdXJllE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGhmaG5ocGggaGlob2hyaIBohWhxaGxoaGhlaH9ogmiEkGgtTnViYYwIZmFpbHVyZXOUXZRoAIwNUmV2aWV3RmFpbHVyZZSTlCmBlH2UKGgFfZQoaGVLAWhmjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjAVzdGFnZZSMCmFzc2Vzc21lbnSUaIRoAIwMRmFpbHVyZUJsb2NrlJOUKYGUfZQoaAV9lCiMDmZhaWx1cmVfcmVhc29ulIwHdGltZW91dJSMDWZhaWx1cmVfY2xhc3OUjBR1cHN0cmVhbV91bmF2YWlsYWJsZZSMCXJldHJ5YWJsZZSIjARoaW50lIw5VGhlIGNoZWNrIHJhbiBvdXQgb2YgdGltZS4gUmV0cnkgaXQ7IG5vdGhpbmcgd2FzIGNoYXJnZWQulIwIZG9jc191cmyUTnVoKX2UaCuPlChonGiXaJ5omWibkGgtTnVidWgpfZRoK4+UKGhmaGVokGiEkGgtTnViYWhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UaIROjAZjbGFpbXOUXZQoaACMC1Jldmlld0NsYWltlJOUKYGUfZQoaAV9lCiMBWluZGV4lEsAaGaMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAlwb3NpdGlvbnOUTowGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKGhpjAVGYWxzZZRoIIwEaGlnaJRobIwKYXNzZXNzbWVudJSMCGlzX2lzc3VllIh1aCl9lGgrj5QoaCBoaWhsaL+QaC1OdWKMCmFzc2Vzc21lbnSUaACMEFJldmlld0Fzc2Vzc21lbnSUk5QpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaGmMBUZhbHNllGggjARoaWdolGiAjCNUd28gcmV2aWV3ZXJzIGZvdW5kIHRoZSBkYXRlIHdyb25nLpSMB2Rpc3NlbnSUjDpPbmUgcmV2aWV3ZXIgcmVhZCB0aGUgY2xhaW0gYXMgYWJvdXQgdGhlIGVudHJ5IGludG8gZm9yY2UulGhwTowKZXJyb3JfY29kZZROjBFpZGVudGlmaWVkX2NsYWltc5RdlCiMIlRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gMjAyNC6UjBhJdCB0b29rIGVmZmVjdCBpbiBNYXJjaC6UZWicjCRUaGlzIHRleHQgaG9sZHMgbW9yZSB0aGFuIG9uZSBjbGFpbS6UaIKMMFRoZSBFVSBBSSBBY3QgZW50ZXJlZCBpbnRvIGZvcmNlIGluIEF1Z3VzdCAyMDI0LpRohE51aCl9lGgrj5QoaJxozGhwaCBoC2hpaM9ogGjOaIJohJBoLU51YmhyaHQpgZR9lChoBX2UKGh4XZSMB3ZlcmRpY3SUYWh7jANjYXCUdWgpfZRoK4+UKGh7aHiQaC1OdWKMDHZlcmlmaWNhdGlvbpROaIVOdWgpfZRoK4+UKGhmaMJocmizaN9ohWi2aLWQaC1OdWJorymBlH2UKGgFfZQoaLNLAWhmjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UaLVOaLZOaMJoxCmBlH2UKGgFfZQoaAuMBmZhaWxlZJRoaU5oIE5ogE5ozE5ocE5ozowHdGltZW91dJRoz12UaJxOaIJOaIRokymBlH2UKGgFfZQoaJeMB3RpbWVvdXSUaJmMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGibiGicjDlUaGUgY2hlY2sgcmFuIG91dCBvZiB0aW1lLiBSZXRyeSBpdDsgbm90aGluZyB3YXMgY2hhcmdlZC6UaJ5OdWgpfZRoK4+UKGicaJdonmiZaJuQaC1OdWJ1aCl9lGgrj5QoaJxozGhwaCBoC2hpaM9ogGjOaIJohJBoLU51YmhyTmjfTmiFTnVoKX2UaCuPlChoZmjCaHJos2jfaIVotmi1kGgtTnViZYwJY2l0YXRpb25zlF2UdWgpfZRoK4+UKGimaIhoEWgLaBVopGheaC5oqmhVaA9oUWisaA1oqGgTaAlo+GhLaAdohJBoLU51Yi4=", + "review__get_citations_clean.json": "gASV2w0AAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLFIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwGMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAowOY2l0YXRpb25fbGltaXSUSxSMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwKMCXVuY2hlY2tlZJRLAGg/SwB1aCl9lGgrj5QoaFZoV2g/kGgtTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhbaE9oS2g1aE5oWmhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwNzaCl9lGgrj5QoaGSQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlIwIZmFpbHVyZXOUXZRoWl2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUXZSMFG1vcmVfY2xhaW1fbG9jYXRpb25zlF2UjA5tb3JlX2NpdGF0aW9uc5RdlIwHZmFpbHVyZZROjAZjbGFpbXOUXZRoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUaACMDFJldmlld1Jlc3VsdJSTlCmBlH2UKGgFfZQojAd2ZXJkaWN0lIwEVHJ1ZZRoIIwEaGlnaJSMBnNvdXJjZZSMCmFzc2Vzc21lbnSUjAhpc19pc3N1ZZSJdWgpfZRoK4+UKGggaIZoiWiLkGgtTnVijAphc3Nlc3NtZW50lGgAjBBSZXZpZXdBc3Nlc3NtZW50lJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGiGjARUcnVllGggjARoaWdolIwJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowQdmVyaWZpY2F0aW9uX3VybJROjAplcnJvcl9jb2RllE6MEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE5odE51aCl9lGgrj5QoaJ1omGiZaCBoC2iGaJtol2iaaJ5odJBoLU51YowKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAtkaXNwb3NpdGlvbpSMDG5vdF9zZWxlY3RlZJR1aCl9lGgrj5QoaKlop5BoLU51YowMdmVyaWZpY2F0aW9ulE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGh9aI5ooWh8aK1ormiAaH+QaC1OdWJhjAljaXRhdGlvbnOUXZQoaACMDlJldmlld0NpdGF0aW9ulJOUKYGUfZQoaAV9lChofEsAjAlyZWZlcmVuY2WUjBphIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeZSMCWNpdGVkX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjANkb2mUTowJc3RhdGVtZW50lIxLVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LCBhY2NvcmRpbmcgdG8gYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnkulIwGcXVvdGVzlF2UjAhwb3NpdGlvbpRoAIwIUG9zaXRpb26Uk5QpgZR9lChoBX2UKIwFc3RhcnSUSwCMA2VuZJRLbowEdGV4dJROdWgpfZRoK4+UKGjHaMhoyZBoLU51YmiAaACMFFJldmlld0NpdGF0aW9uUmVzdWx0lJOUKYGUfZQoaAV9lCiMB2ZpbmRpbmeUjAlzdXBwb3J0ZWSUaImMB3N1cHBvcnSUaIuJdWgpfZRoK4+UKGjRaItoiZBoLU51YowFY2hlY2uUaACME1Jldmlld0NpdGF0aW9uQ2hlY2uUk5QpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUjAlwYWdlX3JlYWSUjARmdWxslIwKcGFnZV90aXRsZZSMJ1BhZ2UgYXQgaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSME3BhZ2VfcHVibGlzaGVkX2RhdGWUTowNcGFnZV9sYW5ndWFnZZSMAmVulIwKc291cmNlX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjA5zb3VyY2VfdmVyc2lvbpROjAdzdXBwb3J0lIwJc3VwcG9ydGVklIwHc25pcHBldJSME1RoZSBzb3VyY2Ugc2F5cyBzby6UaJeME1RoZSBwYWdlIHN0YXRlcyBpdC6UjAVxdW90ZZROjA1taXNzaW5nX3F1b3RllE6MDmRvaV9yZWdpc3RlcmVklE6MCG1ldGFkYXRhlE6MFG1ldGFkYXRhX2RpZmZlcmVuY2VzlF2UjApyZWdpc3RlcmVklE6MEHVuY2hlY2tlZF9yZWFzb26UTmidTmh0TnVoKX2UaCuPlCho4WjzaJdo4mjkaJ1o7mjvaAto7WjwaOxo32jyaOdo3WjmaOlodJBoLU51YnVoKX2UaCuPlChovWiAaLho1mh8aLxov2i6aMGQaC1OdWJotCmBlH2UKGgFfZQoaHxLAWi4jAthIHN0YXRlbWVudJRouowdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaLxOaL2MIlRoZSBhZ2VuY3kgc2FpZCBzbyBpbiBhIHN0YXRlbWVudC6UaL9dlGjBaMMpgZR9lChoBX2UKGjHS29oyEuyaMlOdWgpfZRoK4+UKGjHaMhoyZBoLU51YmiAaM0pgZR9lChoBX2UKGjRjAlzdXBwb3J0ZWSUaImMB3N1cHBvcnSUaIuJdWgpfZRoK4+UKGjRaItoiZBoLU51YmjWaNgpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaN2MBGZ1bGyUaN+MJVBhZ2UgYXQgaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaOFOaOKMAmVulGjkjB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRo5k5o54wJc3VwcG9ydGVklGjpjBNUaGUgc291cmNlIHNheXMgc28ulGiXjBNUaGUgcGFnZSBzdGF0ZXMgaXQulGjsTmjtTmjuTmjvTmjwXZRo8k5o805onU5odE51aCl9lGgrj5QoaOFo82iXaOJo5GidaO5o72gLaO1o8GjsaN9o8mjnaN1o5mjpaHSQaC1OdWJ1aCl9lGgrj5QoaL1ogGi4aNZofGi8aL9oumjBkGgtTnViZXVoKX2UaCuPlChobmhpaBFoC2gVaGxoZ2guaHJoXmgPaFpodWgNaHBoE2gJaLFoS2gHaHSQaC1OdWIu", + "review__get_citations_failed_and_unchecked.json": "gASVUA8AAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMCmluY29tcGxldGWUjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lIwbMjAyNi0xMC0wMVQxMDowNzowMC4xMjM0NTZalIwIbGFuZ3VhZ2WUjAJlbpSMBnBvbGljeZRoAIwQRXNjYWxhdGlvblBvbGljeZSTlCmBlH2UKGgFfZQojAh2ZXJkaWN0c5RdlCiMBUZhbHNllIwMTW9zdGx5IEZhbHNllIwFTWl4ZWSUZYwKY29uZmlkZW5jZZRdlIwDbG93lGGMD21heF9hc3Nlc3NtZW50c5RLFIwRbWF4X3ZlcmlmaWNhdGlvbnOUSwWMBWRlcHRolIwIc3RhbmRhcmSUjA1tYXhfY2l0YXRpb25zlEsUjA1zdWdnZXN0X2VkaXRzlIl1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgbaCVoIGgnaChoJGgjkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjA1SZXZpZXdTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NsYWltc19zZWxlY3RlZJRLAYwLY2xhaW1fbGltaXSUSxSME2NsYWltX2xpbWl0X3JlYWNoZWSUiYwPaW5wdXRfdHJ1bmNhdGVklImMC2Fzc2Vzc21lbnRzlGgAjBZSZXZpZXdBc3Nlc3NtZW50Q291bnRzlJOUKYGUfZQoaAV9lCiMCWNvbXBsZXRlZJRLAYwGZmFpbGVklEsAdWgpfZRoK4+UKGg+aD+QaC1OdWKMDXZlcmlmaWNhdGlvbnOUaACMGFJldmlld1ZlcmlmaWNhdGlvbkNvdW50c5STlCmBlH2UKGgFfZQojAdwbGFubmVklEsAaD5LAGg/SwB1aCl9lGgrj5QoaD5oP2hIkGgtTnVijAZpc3N1ZXOUSwCMD2NpdGF0aW9uc19mb3VuZJRLAowSY2l0YXRpb25zX3NlbGVjdGVklEsCjA5jaXRhdGlvbl9saW1pdJRLFIwWY2l0YXRpb25fbGltaXRfcmVhY2hlZJSJjA9jaXRhdGlvbl9jaGVja3OUaACMGVJldmlld0NpdGF0aW9uQ2hlY2tDb3VudHOUk5QpgZR9lChoBX2UKIwHY2hlY2tlZJRLAIwJdW5jaGVja2VklEsBaD9LAXVoKX2UaCuPlChoVmhXaD+QaC1OdWKMD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKX2UaCuPlChoNGg4aDdoTWhCaFtoT2hLaDVoTmhaaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAXNoKX2UaCuPlChoZJBoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhaXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UaACMFVJldmlld0NpdGF0aW9uRmFpbHVyZZSTlCmBlH2UKGgFfZQojA5jaXRhdGlvbl9pbmRleJRLAIwJcmVmZXJlbmNllIwaYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnmUjAljaXRlZF91cmyUjB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwDZG9plE6MB2ZhaWx1cmWUaACMDEZhaWx1cmVCbG9ja5STlCmBlH2UKGgFfZQojA5mYWlsdXJlX3JlYXNvbpSMCGludGVybmFslIwNZmFpbHVyZV9jbGFzc5SMCGludGVybmFslIwJcmV0cnlhYmxllImMBGhpbnSUjC5UaGUgY2hlY2sgZmFpbGVkIG9uIG91ciBzaWRlLiBUcnkgYWdhaW4gbGF0ZXIulIwIZG9jc191cmyUjCRodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjaW50ZXJuYWyUdWgpfZRoK4+UKGiEaH9ohmiBaIOQaC1OdWJ1aCl9lGgrj5QoaHRoeGhzaHZoeZBoLU51YmGMC21vcmVfY2xhaW1zlF2UjBRtb3JlX2NsYWltX2xvY2F0aW9uc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRoeU6MBmNsYWltc5RdlGgAjAtSZXZpZXdDbGFpbZSTlCmBlH2UKGgFfZQojAVpbmRleJRLAIwFY2xhaW2UjChUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulIwJcG9zaXRpb25zlE6MBnJlc3VsdJRoAIwMUmV2aWV3UmVzdWx0lJOUKYGUfZQoaAV9lCiMB3ZlcmRpY3SUjARUcnVllGggjARoaWdolIwGc291cmNllIwKYXNzZXNzbWVudJSMCGlzX2lzc3VllIl1aCl9lGgrj5QoaCBoo2imaKiQaC1OdWKMCmFzc2Vzc21lbnSUaACMEFJldmlld0Fzc2Vzc21lbnSUk5QpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaKOMBFRydWWUaCCMBGhpZ2iUjAlyYXRpb25hbGWUTowHZGlzc2VudJROjBB2ZXJpZmljYXRpb25fdXJslE6MCmVycm9yX2NvZGWUTowRaWRlbnRpZmllZF9jbGFpbXOUXZRohE6MEXN1Z2dlc3RlZF9yZXdyaXRllE5oeU51aCl9lGgrj5QoaIRotWi2aCBoC2ijaLhotGi3aLpoeZBoLU51YowKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAtkaXNwb3NpdGlvbpSMDG5vdF9zZWxlY3RlZJR1aCl9lGgrj5QoaMVow5BoLU51YowMdmVyaWZpY2F0aW9ulE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGiaaKtovWiZaMloymidaJyQaC1OdWJhjAljaXRhdGlvbnOUXZQoaACMDlJldmlld0NpdGF0aW9ulJOUKYGUfZQoaAV9lChomUsAaHSMGmEgcmVwb3J0IGZyb20gdGhlIG1pbmlzdHJ5lGh2jB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lGh4TowJc3RhdGVtZW50lIxLVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LCBhY2NvcmRpbmcgdG8gYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnkulIwGcXVvdGVzlF2UjAhwb3NpdGlvbpRoAIwIUG9zaXRpb26Uk5QpgZR9lChoBX2UKIwFc3RhcnSUSwCMA2VuZJRLbowEdGV4dJROdWgpfZRoK4+UKGjgaOFo4pBoLU51YmidTowFY2hlY2uUaACME1Jldmlld0NpdGF0aW9uQ2hlY2uUk5QpgZR9lChoBX2UKGgLjAZmYWlsZWSUjAlwYWdlX3JlYWSUTowKcGFnZV90aXRsZZROjBNwYWdlX3B1Ymxpc2hlZF9kYXRllE6MDXBhZ2VfbGFuZ3VhZ2WUTowKc291cmNlX3VybJROjA5zb3VyY2VfdmVyc2lvbpROjAdzdXBwb3J0lE6MB3NuaXBwZXSUTmi0TowFcXVvdGWUTowNbWlzc2luZ19xdW90ZZROjA5kb2lfcmVnaXN0ZXJlZJROjAhtZXRhZGF0YZROjBRtZXRhZGF0YV9kaWZmZXJlbmNlc5RdlIwKcmVnaXN0ZXJlZJROjBB1bmNoZWNrZWRfcmVhc29ulE5ohIwuVGhlIGNoZWNrIGZhaWxlZCBvbiBvdXIgc2lkZS4gVHJ5IGFnYWluIGxhdGVyLpRoeWh7KYGUfZQoaAV9lChof4wIaW50ZXJuYWyUaIGMCGludGVybmFslGiDiWiEjC5UaGUgY2hlY2sgZmFpbGVkIG9uIG91ciBzaWRlLiBUcnkgYWdhaW4gbGF0ZXIulGiGjCRodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjaW50ZXJuYWyUdWgpfZRoK4+UKGiEaH9ohmiBaIOQaC1OdWJ1aCl9lGgrj5QoaO5o+2i0aO9o8GiEaPZo92gLaPVo+Gj0aO1o+mjyaOxo8WjzaHmQaC1OdWJ1aCl9lGgrj5QoaNZonWh0aOVomWh4aNhodmjakGgtTnViaNApgZR9lChoBX2UKGiZSwFodIwLYSBzdGF0ZW1lbnSUaHaMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGh4TmjWjCJUaGUgYWdlbmN5IHNhaWQgc28gaW4gYSBzdGF0ZW1lbnQulGjYXZRo2mjcKYGUfZQoaAV9lCho4EtvaOFLsmjiTnVoKX2UaCuPlCho4GjhaOKQaC1OdWJonWgAjBRSZXZpZXdDaXRhdGlvblJlc3VsdJSTlCmBlH2UKGgFfZQojAdmaW5kaW5nlIwJdW5jaGVja2VklGimTmioiXVoKX2UaCuPlChqGwEAAGioaKaQaC1OdWJo5WjnKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGjsjARmdWxslGjtjCVQYWdlIGF0IGh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGjuTmjvjAJlbpRo8IwdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaPFOaPKMCXVuY2hlY2tlZJRo805otIwTVGhlIHBhZ2Ugc3RhdGVzIGl0LpRo9E5o9U5o9k5o905o+F2UaPpOaPuMB25vX3RleHSUaIROaHlOdWgpfZRoK4+UKGjuaPtotGjvaPBohGj2aPdoC2j1aPho9GjtaPpo8mjsaPFo82h5kGgtTnVidWgpfZRoK4+UKGjWaJ1odGjlaJloeGjYaHZo2pBoLU51YmV1aCl9lGgrj5QoaIxoaWgRaAtoFWhsaGdoLmiQaF5oD2haaJJoDWiOaBNoCWjNaEtoB2h5kGgtTnViLg==", + "review__get_citations_issue_full.json": "gASV2w8AAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMDGlzc3Vlc19mb3VuZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjAhsYW5ndWFnZZSMAmVulIwGcG9saWN5lGgAjBBFc2NhbGF0aW9uUG9saWN5lJOUKYGUfZQoaAV9lCiMCHZlcmRpY3RzlF2UKIwFRmFsc2WUjAxNb3N0bHkgRmFsc2WUjAVNaXhlZJRljApjb25maWRlbmNllF2UjANsb3eUYYwPbWF4X2Fzc2Vzc21lbnRzlEsUjBFtYXhfdmVyaWZpY2F0aW9uc5RLBYwFZGVwdGiUjAhzdGFuZGFyZJSMDW1heF9jaXRhdGlvbnOUSxSMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoJWggaCdoKGgkaCOQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklEsBjAtjbGFpbV9saW1pdJRLFIwTY2xhaW1fbGltaXRfcmVhY2hlZJSJjA9pbnB1dF90cnVuY2F0ZWSUiYwLYXNzZXNzbWVudHOUaACMFlJldmlld0Fzc2Vzc21lbnRDb3VudHOUk5QpgZR9lChoBX2UKIwJY29tcGxldGVklEsBjAZmYWlsZWSUSwB1aCl9lGgrj5QoaD5oP5BoLU51YowNdmVyaWZpY2F0aW9uc5RoAIwYUmV2aWV3VmVyaWZpY2F0aW9uQ291bnRzlJOUKYGUfZQoaAV9lCiMB3BsYW5uZWSUSwBoPksAaD9LAHVoKX2UaCuPlChoPmg/aEiQaC1OdWKMBmlzc3Vlc5RLAIwPY2l0YXRpb25zX2ZvdW5klEsCjBJjaXRhdGlvbnNfc2VsZWN0ZWSUSwKMDmNpdGF0aW9uX2xpbWl0lEsUjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklImMD2NpdGF0aW9uX2NoZWNrc5RoAIwZUmV2aWV3Q2l0YXRpb25DaGVja0NvdW50c5STlCmBlH2UKGgFfZQojAdjaGVja2VklEsCjAl1bmNoZWNrZWSUSwBoP0sAdWgpfZRoK4+UKGhWaFdoP5BoLU51YowPY2l0YXRpb25faXNzdWVzlEsBjBFjaXRhdGlvbnNfc2tpcHBlZJROdWgpfZRoK4+UKGg0aDhoN2hNaEJoW2hPaEtoNWhOaFpoUGhMaDaQaC1OdWKMB2NyZWRpdHOUaACMDVJldmlld0NyZWRpdHOUk5QpgZR9lChoBX2UjAdjaGFyZ2VklEsDc2gpfZRoK4+UKGhkkGgtTnVijBJwb2xsX2FmdGVyX3NlY29uZHOUTmhLXZSMCGZhaWx1cmVzlF2UaFpdlGgAjBNSZXZpZXdDaXRhdGlvbklzc3VllJOUKYGUfZQoaAV9lCiMDmNpdGF0aW9uX2luZGV4lEsAjAlyZWZlcmVuY2WUjBphIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeZSMCWNpdGVkX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjANkb2mUTowJc3RhdGVtZW50lIxLVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LCBhY2NvcmRpbmcgdG8gYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnkulIwGcXVvdGVzlF2UjAhwb3NpdGlvbpRoAIwIUG9zaXRpb26Uk5QpgZR9lChoBX2UKIwFc3RhcnSUSwCMA2VuZJRLbowEdGV4dJROdWgpfZRoK4+UKGiBaIJog5BoLU51YowHZmluZGluZ5SMDGNvbnRyYWRpY3RlZJSMBnNvdXJjZZSMB3N1cHBvcnSUjAdzbmlwcGV0lIwTVGhlIHNvdXJjZSBzYXlzIHNvLpSMCXJhdGlvbmFsZZSME1RoZSBwYWdlIHN0YXRlcyBpdC6UjA1taXNzaW5nX3F1b3RllE6MFG1ldGFkYXRhX2RpZmZlcmVuY2VzlF2UjApwYWdlX3RpdGxllIwnUGFnZSBhdCBodHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwHZmFpbHVyZZROdWgpfZRoK4+UKGh3aI5ocmiPaJFodmhxaIxoeWiIaIZodGiKaJNoe5BoLU51YmGMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UaJNOjAZjbGFpbXOUXZRoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUaACMDFJldmlld1Jlc3VsdJSTlCmBlH2UKGgFfZQojAd2ZXJkaWN0lIwEVHJ1ZZRoIIwEaGlnaJRoiIwKYXNzZXNzbWVudJSMCGlzX2lzc3VllIl1aCl9lGgrj5QoaCBor2iIaLOQaC1OdWKMCmFzc2Vzc21lbnSUaACMEFJldmlld0Fzc2Vzc21lbnSUk5QpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaK+MBFRydWWUaCCMBGhpZ2iUaIxOjAdkaXNzZW50lE6MEHZlcmlmaWNhdGlvbl91cmyUTowKZXJyb3JfY29kZZROjBFpZGVudGlmaWVkX2NsYWltc5RdlIwEaGludJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROaJNOdWgpfZRoK4+UKGjEaL9owGggaAtor2jCaIxowWjFaJOQaC1OdWKMCmVzY2FsYXRpb26UaACMCkVzY2FsYXRpb26Uk5QpgZR9lChoBX2UKIwNbWF0Y2hlZF9ydWxlc5RdlIwLZGlzcG9zaXRpb26UjAxub3Rfc2VsZWN0ZWSUdWgpfZRoK4+UKGjQaM6QaC1OdWKMDHZlcmlmaWNhdGlvbpROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoKX2UaCuPlChopmi2aMhopWjUaNVoqWiokGgtTnViYYwJY2l0YXRpb25zlF2UKGgAjA5SZXZpZXdDaXRhdGlvbpSTlCmBlH2UKGgFfZQoaKVLAGhyjBphIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeZRodIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJRodk5od4xLVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LCBhY2NvcmRpbmcgdG8gYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnkulGh5XZRoe2h9KYGUfZQoaAV9lChogUsAaIJLbmiDTnVoKX2UaCuPlChogWiCaIOQaC1OdWJoqWgAjBRSZXZpZXdDaXRhdGlvblJlc3VsdJSTlCmBlH2UKGgFfZQoaIaMDGNvbnRyYWRpY3RlZJRoiIwHc3VwcG9ydJRos4h1aCl9lGgrj5QoaIZos2iIkGgtTnVijAVjaGVja5RoAIwTUmV2aWV3Q2l0YXRpb25DaGVja5STlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJSMCXBhZ2VfcmVhZJSMBGZ1bGyUaJGMJ1BhZ2UgYXQgaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSME3BhZ2VfcHVibGlzaGVkX2RhdGWUTowNcGFnZV9sYW5ndWFnZZSMAmVulIwKc291cmNlX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjA5zb3VyY2VfdmVyc2lvbpROjAdzdXBwb3J0lIwMY29udHJhZGljdGVklGiKjBNUaGUgc291cmNlIHNheXMgc28ulGiMjBNUaGUgcGFnZSBzdGF0ZXMgaXQulIwFcXVvdGWUTmiOTowOZG9pX3JlZ2lzdGVyZWSUTowIbWV0YWRhdGGUTmiPXZSMCnJlZ2lzdGVyZWSUTowQdW5jaGVja2VkX3JlYXNvbpROaMROaJNOdWgpfZRoK4+UKGj7agoBAABojGj8aP5oxGoGAQAAagcBAABoC2iOaI9qBQEAAGiRagkBAABqAQEAAGj4agABAABoimiTkGgtTnVidWgpfZRoK4+UKGh3aKlocmjxaKVodmh5aHRoe5BoLU51YmjbKYGUfZQoaAV9lChopUsBaHKMC2Egc3RhdGVtZW50lGh0jB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRodk5od4wiVGhlIGFnZW5jeSBzYWlkIHNvIGluIGEgc3RhdGVtZW50LpRoeV2UaHtofSmBlH2UKGgFfZQoaIFLb2iCS7Jog051aCl9lGgrj5QoaIFogmiDkGgtTnViaKlo6SmBlH2UKGgFfZQoaIaMCXN1cHBvcnRlZJRoiIwHc3VwcG9ydJRos4l1aCl9lGgrj5QoaIZos2iIkGgtTnViaPFo8ymBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRo+IwEZnVsbJRokYwlUGFnZSBhdCBodHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRo+05o/IwCZW6UaP6MHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGoAAQAATmoBAQAAjAlzdXBwb3J0ZWSUaIqME1RoZSBzb3VyY2Ugc2F5cyBzby6UaIyME1RoZSBwYWdlIHN0YXRlcyBpdC6UagUBAABOaI5OagYBAABOagcBAABOaI9dlGoJAQAATmoKAQAATmjETmiTTnVoKX2UaCuPlCho+2oKAQAAaIxo/Gj+aMRqBgEAAGoHAQAAaAtojmiPagUBAABokWoJAQAAagEBAABo+GoAAQAAaIpok5BoLU51YnVoKX2UaCuPlChod2ipaHJo8WilaHZoeWh0aHuQaC1OdWJldWgpfZRoK4+UKGiYaGloEWgLaBVolmhnaC5onGheaA9oWmieaA1ommgTaAlo2GhLaAdok5BoLU51Yi4=", + "review__get_citations_issue_issues_view.json": "gASV9AcAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjAZpc3N1ZXOUjAZzdGF0dXOUjAljb21wbGV0ZWSUjAdvdXRjb21llIwMaXNzdWVzX2ZvdW5klIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLFIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwGMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAowOY2l0YXRpb25fbGltaXSUSxSMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwKMCXVuY2hlY2tlZJRLAGg/SwB1aCl9lGgrj5QoaFZoV2g/kGgtTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwGMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhbaE9oS2g1aE5oWmhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwNzaCl9lGgrj5QoaGSQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlIwIZmFpbHVyZXOUXZRoWl2UaACME1Jldmlld0NpdGF0aW9uSXNzdWWUk5QpgZR9lChoBX2UKIwOY2l0YXRpb25faW5kZXiUSwCMCXJlZmVyZW5jZZSMGmEgcmVwb3J0IGZyb20gdGhlIG1pbmlzdHJ5lIwJY2l0ZWRfdXJslIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMA2RvaZROjAlzdGF0ZW1lbnSUjEtVbmVtcGxveW1lbnQgZmVsbCB0byA0LjElIGluIDIwMjQsIGFjY29yZGluZyB0byBhIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeS6UjAZxdW90ZXOUXZSMCHBvc2l0aW9ulGgAjAhQb3NpdGlvbpSTlCmBlH2UKGgFfZQojAVzdGFydJRLAIwDZW5klEtujAR0ZXh0lE51aCl9lGgrj5QoaIFogmiDkGgtTnVijAdmaW5kaW5nlIwMY29udHJhZGljdGVklIwGc291cmNllIwHc3VwcG9ydJSMB3NuaXBwZXSUjBNUaGUgc291cmNlIHNheXMgc28ulIwJcmF0aW9uYWxllIwTVGhlIHBhZ2Ugc3RhdGVzIGl0LpSMDW1pc3NpbmdfcXVvdGWUTowUbWV0YWRhdGFfZGlmZmVyZW5jZXOUXZSMCnBhZ2VfdGl0bGWUjCdQYWdlIGF0IGh0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjAdmYWlsdXJllE51aCl9lGgrj5QoaHdojmhyaI9okWh2aHFojGh5aIhohmh0aIpok2h7kGgtTnViYYwRY2l0YXRpb25fZmFpbHVyZXOUXZSMC21vcmVfY2xhaW1zlF2UjBRtb3JlX2NsYWltX2xvY2F0aW9uc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRok06MBmNsYWltc5RdlIwJY2l0YXRpb25zlF2UdWgpfZRoK4+UKGiYaGloEWgLaBVolmhnaC5onGheaA9oWmgNaJpoE2gJaEtoB2iTkGgtTnViLg==", + "review__get_citations_limit_exactly_at_limit.json": "gASV2w0AAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAowNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwGMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAowOY2l0YXRpb25fbGltaXSUSwKMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwKMCXVuY2hlY2tlZJRLAGg/SwB1aCl9lGgrj5QoaFZoV2g/kGgtTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhbaE9oS2g1aE5oWmhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwNzaCl9lGgrj5QoaGSQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlIwIZmFpbHVyZXOUXZRoWl2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUXZSMFG1vcmVfY2xhaW1fbG9jYXRpb25zlF2UjA5tb3JlX2NpdGF0aW9uc5RdlIwHZmFpbHVyZZROjAZjbGFpbXOUXZRoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUaACMDFJldmlld1Jlc3VsdJSTlCmBlH2UKGgFfZQojAd2ZXJkaWN0lIwEVHJ1ZZRoIIwEaGlnaJSMBnNvdXJjZZSMCmFzc2Vzc21lbnSUjAhpc19pc3N1ZZSJdWgpfZRoK4+UKGggaIZoiWiLkGgtTnVijAphc3Nlc3NtZW50lGgAjBBSZXZpZXdBc3Nlc3NtZW50lJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGiGjARUcnVllGggjARoaWdolIwJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowQdmVyaWZpY2F0aW9uX3VybJROjAplcnJvcl9jb2RllE6MEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE5odE51aCl9lGgrj5QoaJ1omGiZaCBoC2iGaJtol2iaaJ5odJBoLU51YowKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAtkaXNwb3NpdGlvbpSMDG5vdF9zZWxlY3RlZJR1aCl9lGgrj5QoaKlop5BoLU51YowMdmVyaWZpY2F0aW9ulE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGh9aI5ooWh8aK1ormiAaH+QaC1OdWJhjAljaXRhdGlvbnOUXZQoaACMDlJldmlld0NpdGF0aW9ulJOUKYGUfZQoaAV9lChofEsAjAlyZWZlcmVuY2WUjBphIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeZSMCWNpdGVkX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjANkb2mUTowJc3RhdGVtZW50lIxLVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LCBhY2NvcmRpbmcgdG8gYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnkulIwGcXVvdGVzlF2UjAhwb3NpdGlvbpRoAIwIUG9zaXRpb26Uk5QpgZR9lChoBX2UKIwFc3RhcnSUSwCMA2VuZJRLbowEdGV4dJROdWgpfZRoK4+UKGjHaMhoyZBoLU51YmiAaACMFFJldmlld0NpdGF0aW9uUmVzdWx0lJOUKYGUfZQoaAV9lCiMB2ZpbmRpbmeUjAlzdXBwb3J0ZWSUaImMB3N1cHBvcnSUaIuJdWgpfZRoK4+UKGjRaItoiZBoLU51YowFY2hlY2uUaACME1Jldmlld0NpdGF0aW9uQ2hlY2uUk5QpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUjAlwYWdlX3JlYWSUjARmdWxslIwKcGFnZV90aXRsZZSMJ1BhZ2UgYXQgaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSME3BhZ2VfcHVibGlzaGVkX2RhdGWUTowNcGFnZV9sYW5ndWFnZZSMAmVulIwKc291cmNlX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjA5zb3VyY2VfdmVyc2lvbpROjAdzdXBwb3J0lIwJc3VwcG9ydGVklIwHc25pcHBldJSME1RoZSBzb3VyY2Ugc2F5cyBzby6UaJeME1RoZSBwYWdlIHN0YXRlcyBpdC6UjAVxdW90ZZROjA1taXNzaW5nX3F1b3RllE6MDmRvaV9yZWdpc3RlcmVklE6MCG1ldGFkYXRhlE6MFG1ldGFkYXRhX2RpZmZlcmVuY2VzlF2UjApyZWdpc3RlcmVklE6MEHVuY2hlY2tlZF9yZWFzb26UTmidTmh0TnVoKX2UaCuPlCho4WjzaJdo4mjkaJ1o7mjvaAto7WjwaOxo32jyaOdo3WjmaOlodJBoLU51YnVoKX2UaCuPlChovWiAaLho1mh8aLxov2i6aMGQaC1OdWJotCmBlH2UKGgFfZQoaHxLAWi4jAthIHN0YXRlbWVudJRouowdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaLxOaL2MIlRoZSBhZ2VuY3kgc2FpZCBzbyBpbiBhIHN0YXRlbWVudC6UaL9dlGjBaMMpgZR9lChoBX2UKGjHS29oyEuyaMlOdWgpfZRoK4+UKGjHaMhoyZBoLU51YmiAaM0pgZR9lChoBX2UKGjRjAlzdXBwb3J0ZWSUaImMB3N1cHBvcnSUaIuJdWgpfZRoK4+UKGjRaItoiZBoLU51YmjWaNgpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaN2MBGZ1bGyUaN+MJVBhZ2UgYXQgaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaOFOaOKMAmVulGjkjB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRo5k5o54wJc3VwcG9ydGVklGjpjBNUaGUgc291cmNlIHNheXMgc28ulGiXjBNUaGUgcGFnZSBzdGF0ZXMgaXQulGjsTmjtTmjuTmjvTmjwXZRo8k5o805onU5odE51aCl9lGgrj5QoaOFo82iXaOJo5GidaO5o72gLaO1o8GjsaN9o8mjnaN1o5mjpaHSQaC1OdWJ1aCl9lGgrj5QoaL1ogGi4aNZofGi8aL9oumjBkGgtTnViZXVoKX2UaCuPlChobmhpaBFoC2gVaGxoZ2guaHJoXmgPaFpodWgNaHBoE2gJaLFoS2gHaHSQaC1OdWIu", + "review__get_citations_limit_reached.json": "gASVqQwAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAYwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwGMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAYwOY2l0YXRpb25fbGltaXSUSwGMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiIwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwGMCXVuY2hlY2tlZJRLAGg/SwB1aCl9lGgrj5QoaFZoV2g/kGgtTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhbaE9oS2g1aE5oWmhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwJzaCl9lGgrj5QoaGSQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlIwIZmFpbHVyZXOUXZRoWl2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUXZSMFG1vcmVfY2xhaW1fbG9jYXRpb25zlF2UjA5tb3JlX2NpdGF0aW9uc5RdlGgAjBJSZXZpZXdNb3JlQ2l0YXRpb26Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwGMCXJlZmVyZW5jZZSMC2Egc3RhdGVtZW50lIwJY2l0ZWRfdXJslIwdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUjANkb2mUTowIc2VudGVuY2WUjCJUaGUgYWdlbmN5IHNhaWQgc28gaW4gYSBzdGF0ZW1lbnQulIwIcG9zaXRpb26UaACMCFBvc2l0aW9ulJOUKYGUfZQoaAV9lCiMBXN0YXJ0lEtvjANlbmSUS7KMBHRleHSUTnVoKX2UaCuPlChoh2iIaImQaC1OdWJ1aCl9lGgrj5QoaHpof2h5aH5ofGiBkGgtTnViYYwHZmFpbHVyZZROjAZjbGFpbXOUXZRoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKGh5SwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUaACMDFJldmlld1Jlc3VsdJSTlCmBlH2UKGgFfZQojAd2ZXJkaWN0lIwEVHJ1ZZRoIIwEaGlnaJSMBnNvdXJjZZSMCmFzc2Vzc21lbnSUjAhpc19pc3N1ZZSJdWgpfZRoK4+UKGggaJ9oomikkGgtTnVijAphc3Nlc3NtZW50lGgAjBBSZXZpZXdBc3Nlc3NtZW50lJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGifjARUcnVllGggjARoaWdolIwJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowQdmVyaWZpY2F0aW9uX3VybJROjAplcnJvcl9jb2RllE6MEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE5ojk51aCl9lGgrj5QoaLZosWiyaCBoC2ifaLRosGizaLdojpBoLU51YowKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAtkaXNwb3NpdGlvbpSMDG5vdF9zZWxlY3RlZJR1aCl9lGgrj5QoaMJowJBoLU51YowMdmVyaWZpY2F0aW9ulE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGiWaKdoumh5aMZox2iZaJiQaC1OdWJhjAljaXRhdGlvbnOUXZRoAIwOUmV2aWV3Q2l0YXRpb26Uk5QpgZR9lChoBX2UKGh5SwBoeowaYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnmUaHyMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUaH5OjAlzdGF0ZW1lbnSUjEtVbmVtcGxveW1lbnQgZmVsbCB0byA0LjElIGluIDIwMjQsIGFjY29yZGluZyB0byBhIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeS6UjAZxdW90ZXOUXZRogWiDKYGUfZQoaAV9lChoh0sAaIhLbmiJTnVoKX2UaCuPlChoh2iIaImQaC1OdWJomWgAjBRSZXZpZXdDaXRhdGlvblJlc3VsdJSTlCmBlH2UKGgFfZQojAdmaW5kaW5nlIwJc3VwcG9ydGVklGiijAdzdXBwb3J0lGikiXVoKX2UaCuPlCho4WikaKKQaC1OdWKMBWNoZWNrlGgAjBNSZXZpZXdDaXRhdGlvbkNoZWNrlJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklIwJcGFnZV9yZWFklIwEZnVsbJSMCnBhZ2VfdGl0bGWUjCdQYWdlIGF0IGh0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjBNwYWdlX3B1Ymxpc2hlZF9kYXRllE6MDXBhZ2VfbGFuZ3VhZ2WUjAJlbpSMCnNvdXJjZV91cmyUjB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwOc291cmNlX3ZlcnNpb26UTowHc3VwcG9ydJSMCXN1cHBvcnRlZJSMB3NuaXBwZXSUjBNUaGUgc291cmNlIHNheXMgc28ulGiwjBNUaGUgcGFnZSBzdGF0ZXMgaXQulIwFcXVvdGWUTowNbWlzc2luZ19xdW90ZZROjA5kb2lfcmVnaXN0ZXJlZJROjAhtZXRhZGF0YZROjBRtZXRhZGF0YV9kaWZmZXJlbmNlc5RdlIwKcmVnaXN0ZXJlZJROjBB1bmNoZWNrZWRfcmVhc29ulE5otk5ojk51aCl9lGgrj5QoaPFqAwEAAGiwaPJo9Gi2aP5o/2gLaP1qAAEAAGj8aO9qAgEAAGj3aO1o9mj5aI6QaC1OdWJ1aCl9lGgrj5QoaNNomWh6aOZoeWh+aNVofGiBkGgtTnViYXVoKX2UaCuPlChobmhpaBFoC2gVaGxoZ2guaHJoXmgPaFpoj2gNaHBoE2gJaMpoS2gHaI6QaC1OdWIu", + "review__get_citations_no_claim_but_citations.json": "gASVkAsAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLFIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwCMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwCMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAowOY2l0YXRpb25fbGltaXSUSxSMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwKMCXVuY2hlY2tlZJRLAGg/SwB1aCl9lGgrj5QoaFZoV2g/kGgtTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhbaE9oS2g1aE5oWmhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwJzaCl9lGgrj5QoaGSQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlIwIZmFpbHVyZXOUXZRoWl2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUXZSMFG1vcmVfY2xhaW1fbG9jYXRpb25zlF2UjA5tb3JlX2NpdGF0aW9uc5RdlIwHZmFpbHVyZZROjAZjbGFpbXOUXZSMCWNpdGF0aW9uc5RdlChoAIwOUmV2aWV3Q2l0YXRpb26Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMCXJlZmVyZW5jZZSMGmEgcmVwb3J0IGZyb20gdGhlIG1pbmlzdHJ5lIwJY2l0ZWRfdXJslIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMA2RvaZROjAlzdGF0ZW1lbnSUjEtVbmVtcGxveW1lbnQgZmVsbCB0byA0LjElIGluIDIwMjQsIGFjY29yZGluZyB0byBhIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeS6UjAZxdW90ZXOUXZSMCHBvc2l0aW9ulGgAjAhQb3NpdGlvbpSTlCmBlH2UKGgFfZQojAVzdGFydJRLAIwDZW5klEtujAR0ZXh0lE51aCl9lGgrj5QoaI5oj2iQkGgtTnVijAZyZXN1bHSUaACMFFJldmlld0NpdGF0aW9uUmVzdWx0lJOUKYGUfZQoaAV9lCiMB2ZpbmRpbmeUjAlzdXBwb3J0ZWSUjAZzb3VyY2WUjAdzdXBwb3J0lIwIaXNfaXNzdWWUiXVoKX2UaCuPlChomWidaJuQaC1OdWKMBWNoZWNrlGgAjBNSZXZpZXdDaXRhdGlvbkNoZWNrlJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklIwJcGFnZV9yZWFklIwEZnVsbJSMCnBhZ2VfdGl0bGWUjCdQYWdlIGF0IGh0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjBNwYWdlX3B1Ymxpc2hlZF9kYXRllE6MDXBhZ2VfbGFuZ3VhZ2WUjAJlbpSMCnNvdXJjZV91cmyUjB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwOc291cmNlX3ZlcnNpb26UTowHc3VwcG9ydJSMCXN1cHBvcnRlZJSMB3NuaXBwZXSUjBNUaGUgc291cmNlIHNheXMgc28ulIwJcmF0aW9uYWxllIwTVGhlIHBhZ2Ugc3RhdGVzIGl0LpSMBXF1b3RllE6MDW1pc3NpbmdfcXVvdGWUTowOZG9pX3JlZ2lzdGVyZWSUTowIbWV0YWRhdGGUTowUbWV0YWRhdGFfZGlmZmVyZW5jZXOUXZSMCnJlZ2lzdGVyZWSUTowQdW5jaGVja2VkX3JlYXNvbpROjARoaW50lE5odE51aCl9lGgrj5QoaKtovmi1aKxormi/aLloumgLaLhou2i3aKlovWixaKdosGizaHSQaC1OdWJ1aCl9lGgrj5QoaIRok2h/aKBofmiDaIZogWiIkGgtTnViaHopgZR9lChoBX2UKGh+SwFof4wLYSBzdGF0ZW1lbnSUaIGMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGiDTmiEjCJUaGUgYWdlbmN5IHNhaWQgc28gaW4gYSBzdGF0ZW1lbnQulGiGXZRoiGiKKYGUfZQoaAV9lChojktvaI9LsmiQTnVoKX2UaCuPlChojmiPaJCQaC1OdWJok2iVKYGUfZQoaAV9lChomYwJc3VwcG9ydGVklGibjAdzdXBwb3J0lGidiXVoKX2UaCuPlChomWidaJuQaC1OdWJooGiiKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGinjARmdWxslGipjCVQYWdlIGF0IGh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGirTmisjAJlbpRorowdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaLBOaLGMCXN1cHBvcnRlZJRos4wTVGhlIHNvdXJjZSBzYXlzIHNvLpRotYwTVGhlIHBhZ2Ugc3RhdGVzIGl0LpRot05ouE5ouU5ouk5ou12UaL1OaL5OaL9OaHROdWgpfZRoK4+UKGiraL5otWisaK5ov2i5aLpoC2i4aLtot2ipaL1osWinaLBos2h0kGgtTnVidWgpfZRoK4+UKGiEaJNof2igaH5og2iGaIFoiJBoLU51YmV1aCl9lGgrj5QoaG5oaWgRaAtoFWhsaGdoLmhyaF5oD2haaHVoDWhwaBNoCWh3aEtoB2h0kGgtTnViLg==", + "review__get_citations_no_claim_no_citation.json": "gASV+AUAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwGZmFpbGVklIwHb3V0Y29tZZSMCXVuY2hlY2tlZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjAhsYW5ndWFnZZSMAmVulIwGcG9saWN5lGgAjBBFc2NhbGF0aW9uUG9saWN5lJOUKYGUfZQoaAV9lCiMCHZlcmRpY3RzlF2UKIwFRmFsc2WUjAxNb3N0bHkgRmFsc2WUjAVNaXhlZJRljApjb25maWRlbmNllF2UjANsb3eUYYwPbWF4X2Fzc2Vzc21lbnRzlEsUjBFtYXhfdmVyaWZpY2F0aW9uc5RLBYwFZGVwdGiUjAhzdGFuZGFyZJSMDW1heF9jaXRhdGlvbnOUSxSMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoJWggaCdoKGgkaCOQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklE6MC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklE6MD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5ROjA12ZXJpZmljYXRpb25zlE6MBmlzc3Vlc5RLAIwPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJRLFIwWY2l0YXRpb25fbGltaXRfcmVhY2hlZJROjA9jaXRhdGlvbl9jaGVja3OUTowPY2l0YXRpb25faXNzdWVzlEsAjBFjaXRhdGlvbnNfc2tpcHBlZJROdWgpfZRoK4+UKGg0aDhoN2g8aDloQWg+aDpoNWg9aEBoP2g7aDaQaC1OdWKMB2NyZWRpdHOUaACMDVJldmlld0NyZWRpdHOUk5QpgZR9lChoBX2UjAdjaGFyZ2VklEsAc2gpfZRoK4+UKGhKkGgtTnVijBJwb2xsX2FmdGVyX3NlY29uZHOUTmg6XZSMCGZhaWx1cmVzlF2UaEBdlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMC21vcmVfY2xhaW1zlE6MFG1vcmVfY2xhaW1fbG9jYXRpb25zlE6MDm1vcmVfY2l0YXRpb25zlE6MB2ZhaWx1cmWUaACMDEZhaWx1cmVCbG9ja5STlCmBlH2UKGgFfZQojA5mYWlsdXJlX3JlYXNvbpSMCG5vX2NsYWltlIwNZmFpbHVyZV9jbGFzc5SMDWludmFsaWRfaW5wdXSUjAlyZXRyeWFibGWUiYwEaGludJSMo05vIGZhY3R1YWwgc3RhdGVtZW50IHRoYXQgY2FuIGJlIGNoZWNrZWQgYWdhaW5zdCBldmlkZW5jZSB3YXMgZm91bmQgaW4gdGhlIGlucHV0LiBTZW5kIG9uZSBmYWN0dWFsIGNsYWltLCBvciBydW4gdGhlIHRleHQgdGhyb3VnaCAvZXh0cmFjdCB0byBlbnVtZXJhdGUgaXRzIGNsYWltcy6UjAhkb2NzX3VybJSMKWh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyNpbnZhbGlkLWlucHV0lHVoKX2UaCuPlChoYmhdaGRoX2hhkGgtTnVijAZjbGFpbXOUXZSMCWNpdGF0aW9uc5RdlHVoKX2UaCuPlChoVGhPaBFoC2gVaFJoTWguaFZoRGgPaEBoaGgNaFVoE2gJaGpoOmgHaFeQaC1OdWIu", + "review__get_citations_not_asked.json": "gASVtAcAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwGMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKX2UaCuPlChoNGg4aDdoTWhCaFJoT2hLaDVoTmhRaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAXNoKX2UaCuPlChoW5BoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UjAdmYWlsdXJllE6MBmNsYWltc5RdlGgAjAtSZXZpZXdDbGFpbZSTlCmBlH2UKGgFfZQojAVpbmRleJRLAIwFY2xhaW2UjChUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulIwJcG9zaXRpb25zlE6MBnJlc3VsdJRoAIwMUmV2aWV3UmVzdWx0lJOUKYGUfZQoaAV9lCiMB3ZlcmRpY3SUjARUcnVllGggjARoaWdolIwGc291cmNllIwKYXNzZXNzbWVudJSMCGlzX2lzc3VllIl1aCl9lGgrj5QoaCBofWiAaIKQaC1OdWKMCmFzc2Vzc21lbnSUaACMEFJldmlld0Fzc2Vzc21lbnSUk5QpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaH2MBFRydWWUaCCMBGhpZ2iUjAlyYXRpb25hbGWUTowHZGlzc2VudJROjBB2ZXJpZmljYXRpb25fdXJslE6MCmVycm9yX2NvZGWUTowRaWRlbnRpZmllZF9jbGFpbXOUXZSMBGhpbnSUTowRc3VnZ2VzdGVkX3Jld3JpdGWUTmhrTnVoKX2UaCuPlCholGiPaJBoIGgLaH1okmiOaJFolWhrkGgtTnVijAplc2NhbGF0aW9ulGgAjApFc2NhbGF0aW9ulJOUKYGUfZQoaAV9lCiMDW1hdGNoZWRfcnVsZXOUXZSMC2Rpc3Bvc2l0aW9ulIwMbm90X3NlbGVjdGVklHVoKX2UaCuPlChooGiekGgtTnVijAx2ZXJpZmljYXRpb26UTowPc3VnZ2VzdGVkX2VkaXRzlE51aCl9lGgrj5QoaHRohWiYaHNopGilaHdodpBoLU51YmGMCWNpdGF0aW9uc5RdlHVoKX2UaCuPlChoZWhgaBFoC2gVaGNoXmguaGloVWgPaFFobGgNaGdoE2gJaKhoS2gHaGuQaC1OdWIu", + "review__get_citations_only.json": "gASVMAwAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSwCMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLFIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwCMC2NsYWltX2xpbWl0lEsAjBNjbGFpbV9saW1pdF9yZWFjaGVklIiMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwCMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAowOY2l0YXRpb25fbGltaXSUSxSMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwKMCXVuY2hlY2tlZJRLAGg/SwB1aCl9lGgrj5QoaFZoV2g/kGgtTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhbaE9oS2g1aE5oWmhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwJzaCl9lGgrj5QoaGSQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlIwIZmFpbHVyZXOUXZRoWl2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUXZSMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UYYwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZRoAIwNQ2xhaW1Mb2NhdGlvbpSTlCmBlH2UKGgFfZQojAVjbGFpbZSMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAlwb3NpdGlvbnOUTnVoKX2UaCuPlChoeGh6kGgtTnViYYwObW9yZV9jaXRhdGlvbnOUXZSMB2ZhaWx1cmWUTowGY2xhaW1zlF2UjAljaXRhdGlvbnOUXZQoaACMDlJldmlld0NpdGF0aW9ulJOUKYGUfZQoaAV9lCiMBWluZGV4lEsAjAlyZWZlcmVuY2WUjBphIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeZSMCWNpdGVkX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjANkb2mUTowJc3RhdGVtZW50lIxLVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LCBhY2NvcmRpbmcgdG8gYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnkulIwGcXVvdGVzlF2UjAhwb3NpdGlvbpRoAIwIUG9zaXRpb26Uk5QpgZR9lChoBX2UKIwFc3RhcnSUSwCMA2VuZJRLbowEdGV4dJROdWgpfZRoK4+UKGiZaJpom5BoLU51YowGcmVzdWx0lGgAjBRSZXZpZXdDaXRhdGlvblJlc3VsdJSTlCmBlH2UKGgFfZQojAdmaW5kaW5nlIwJc3VwcG9ydGVklIwGc291cmNllIwHc3VwcG9ydJSMCGlzX2lzc3VllIl1aCl9lGgrj5QoaKRoqGimkGgtTnVijAVjaGVja5RoAIwTUmV2aWV3Q2l0YXRpb25DaGVja5STlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJSMCXBhZ2VfcmVhZJSMBGZ1bGyUjApwYWdlX3RpdGxllIwnUGFnZSBhdCBodHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwTcGFnZV9wdWJsaXNoZWRfZGF0ZZROjA1wYWdlX2xhbmd1YWdllIwCZW6UjApzb3VyY2VfdXJslIwfaHR0cHM6Ly9leGFtcGxlLmdvdi9yZXBvcnQtMjAyNJSMDnNvdXJjZV92ZXJzaW9ulE6MB3N1cHBvcnSUjAlzdXBwb3J0ZWSUjAdzbmlwcGV0lIwTVGhlIHNvdXJjZSBzYXlzIHNvLpSMCXJhdGlvbmFsZZSME1RoZSBwYWdlIHN0YXRlcyBpdC6UjAVxdW90ZZROjA1taXNzaW5nX3F1b3RllE6MDmRvaV9yZWdpc3RlcmVklE6MCG1ldGFkYXRhlE6MFG1ldGFkYXRhX2RpZmZlcmVuY2VzlF2UjApyZWdpc3RlcmVklE6MEHVuY2hlY2tlZF9yZWFzb26UTowEaGludJROaH9OdWgpfZRoK4+UKGi2aMlowGi3aLloymjEaMVoC2jDaMZowmi0aMhovGiyaLtovmh/kGgtTnVidWgpfZRoK4+UKGiPaJ5oimiraIlojmiRaIxok5BoLU51YmiFKYGUfZQoaAV9lChoiUsBaIqMC2Egc3RhdGVtZW50lGiMjB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRojk5oj4wiVGhlIGFnZW5jeSBzYWlkIHNvIGluIGEgc3RhdGVtZW50LpRokV2UaJNolSmBlH2UKGgFfZQoaJlLb2iaS7Jom051aCl9lGgrj5QoaJlommibkGgtTnViaJ5ooCmBlH2UKGgFfZQoaKSMCXN1cHBvcnRlZJRopowHc3VwcG9ydJRoqIl1aCl9lGgrj5QoaKRoqGimkGgtTnViaKtorSmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRosowEZnVsbJRotIwlUGFnZSBhdCBodHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRotk5ot4wCZW6UaLmMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGi7Tmi8jAlzdXBwb3J0ZWSUaL6ME1RoZSBzb3VyY2Ugc2F5cyBzby6UaMCME1RoZSBwYWdlIHN0YXRlcyBpdC6UaMJOaMNOaMROaMVOaMZdlGjITmjJTmjKTmh/TnVoKX2UaCuPlChotmjJaMBot2i5aMpoxGjFaAtow2jGaMJotGjIaLxosmi7aL5of5BoLU51YnVoKX2UaCuPlChoj2ieaIpoq2iJaI5okWiMaJOQaC1OdWJldWgpfZRoK4+UKGhuaGloEWgLaBVobGhnaC5ofWheaA9oWmiAaA1ocWgTaAlogmhLaAdof5BoLU51Yi4=", + "review__get_citations_partly_supported.json": "gASV6Q0AAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLFIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwGMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAowOY2l0YXRpb25fbGltaXSUSxSMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwKMCXVuY2hlY2tlZJRLAGg/SwB1aCl9lGgrj5QoaFZoV2g/kGgtTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhbaE9oS2g1aE5oWmhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwNzaCl9lGgrj5QoaGSQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlIwIZmFpbHVyZXOUXZRoWl2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUXZSMFG1vcmVfY2xhaW1fbG9jYXRpb25zlF2UjA5tb3JlX2NpdGF0aW9uc5RdlIwHZmFpbHVyZZROjAZjbGFpbXOUXZRoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUaACMDFJldmlld1Jlc3VsdJSTlCmBlH2UKGgFfZQojAd2ZXJkaWN0lIwEVHJ1ZZRoIIwEaGlnaJSMBnNvdXJjZZSMCmFzc2Vzc21lbnSUjAhpc19pc3N1ZZSJdWgpfZRoK4+UKGggaIZoiWiLkGgtTnVijAphc3Nlc3NtZW50lGgAjBBSZXZpZXdBc3Nlc3NtZW50lJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGiGjARUcnVllGggjARoaWdolIwJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowQdmVyaWZpY2F0aW9uX3VybJROjAplcnJvcl9jb2RllE6MEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE5odE51aCl9lGgrj5QoaJ1omGiZaCBoC2iGaJtol2iaaJ5odJBoLU51YowKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAtkaXNwb3NpdGlvbpSMDG5vdF9zZWxlY3RlZJR1aCl9lGgrj5QoaKlop5BoLU51YowMdmVyaWZpY2F0aW9ulE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGh9aI5ooWh8aK1ormiAaH+QaC1OdWJhjAljaXRhdGlvbnOUXZQoaACMDlJldmlld0NpdGF0aW9ulJOUKYGUfZQoaAV9lChofEsAjAlyZWZlcmVuY2WUjBphIHJlcG9ydCBmcm9tIHRoZSBtaW5pc3RyeZSMCWNpdGVkX3VybJSMH2h0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjANkb2mUTowJc3RhdGVtZW50lIxLVW5lbXBsb3ltZW50IGZlbGwgdG8gNC4xJSBpbiAyMDI0LCBhY2NvcmRpbmcgdG8gYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnkulIwGcXVvdGVzlF2UjAhwb3NpdGlvbpRoAIwIUG9zaXRpb26Uk5QpgZR9lChoBX2UKIwFc3RhcnSUSwCMA2VuZJRLbowEdGV4dJROdWgpfZRoK4+UKGjHaMhoyZBoLU51YmiAaACMFFJldmlld0NpdGF0aW9uUmVzdWx0lJOUKYGUfZQoaAV9lCiMB2ZpbmRpbmeUjBBwYXJ0bHlfc3VwcG9ydGVklGiJjAdzdXBwb3J0lGiLiXVoKX2UaCuPlCho0WiLaImQaC1OdWKMBWNoZWNrlGgAjBNSZXZpZXdDaXRhdGlvbkNoZWNrlJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklIwJcGFnZV9yZWFklIwEZnVsbJSMCnBhZ2VfdGl0bGWUjCdQYWdlIGF0IGh0dHBzOi8vZXhhbXBsZS5nb3YvcmVwb3J0LTIwMjSUjBNwYWdlX3B1Ymxpc2hlZF9kYXRllE6MDXBhZ2VfbGFuZ3VhZ2WUjAJlbpSMCnNvdXJjZV91cmyUjB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwOc291cmNlX3ZlcnNpb26UTowHc3VwcG9ydJSMEHBhcnRseV9zdXBwb3J0ZWSUjAdzbmlwcGV0lIwTVGhlIHNvdXJjZSBzYXlzIHNvLpRol4wTVGhlIHBhZ2Ugc3RhdGVzIGl0LpSMBXF1b3RllE6MDW1pc3NpbmdfcXVvdGWUTowOZG9pX3JlZ2lzdGVyZWSUTowIbWV0YWRhdGGUTowUbWV0YWRhdGFfZGlmZmVyZW5jZXOUXZSMCnJlZ2lzdGVyZWSUTowQdW5jaGVja2VkX3JlYXNvbpROaJ1OaHROdWgpfZRoK4+UKGjhaPNol2jiaORonWjuaO9oC2jtaPBo7GjfaPJo52jdaOZo6Wh0kGgtTnVidWgpfZRoK4+UKGi9aIBouGjWaHxovGi/aLpowZBoLU51Ymi0KYGUfZQoaAV9lChofEsBaLiMC2Egc3RhdGVtZW50lGi6jB1odHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRovE5ovYwiVGhlIGFnZW5jeSBzYWlkIHNvIGluIGEgc3RhdGVtZW50LpRov12UaMFowymBlH2UKGgFfZQoaMdLb2jIS7JoyU51aCl9lGgrj5QoaMdoyGjJkGgtTnViaIBozSmBlH2UKGgFfZQoaNGMCXN1cHBvcnRlZJRoiYwHc3VwcG9ydJRoi4l1aCl9lGgrj5QoaNFoi2iJkGgtTnViaNZo2CmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRo3YwEZnVsbJRo34wlUGFnZSBhdCBodHRwczovL2V4YW1wbGUub3JnL3N0YXRlbWVudJRo4U5o4owCZW6UaOSMHWh0dHBzOi8vZXhhbXBsZS5vcmcvc3RhdGVtZW50lGjmTmjnjAlzdXBwb3J0ZWSUaOmME1RoZSBzb3VyY2Ugc2F5cyBzby6UaJeME1RoZSBwYWdlIHN0YXRlcyBpdC6UaOxOaO1OaO5OaO9OaPBdlGjyTmjzTmidTmh0TnVoKX2UaCuPlCho4WjzaJdo4mjkaJ1o7mjvaAto7WjwaOxo32jyaOdo3WjmaOlodJBoLU51YnVoKX2UaCuPlChovWiAaLho1mh8aLxov2i6aMGQaC1OdWJldWgpfZRoK4+UKGhuaGloEWgLaBVobGhnaC5ocmheaA9oWmh1aA1ocGgTaAlosWhLaAdodJBoLU51Yi4=", + "review__get_citations_running.json": "gASVIAsAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJdmVyaWZ5aW5nlIwHb3V0Y29tZZROjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLFIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGWgjaB5oJWgmaCJoIZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwGMBmZhaWxlZJRLAHVoJ32UaCmPlChoPGg9kGgrTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg8SwBoPUsAdWgnfZRoKY+UKGg8aD1oRpBoK051YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUSwKMEmNpdGF0aW9uc19zZWxlY3RlZJRLAowOY2l0YXRpb25fbGltaXSUSxSMFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUiYwPY2l0YXRpb25fY2hlY2tzlGgAjBlSZXZpZXdDaXRhdGlvbkNoZWNrQ291bnRzlJOUKYGUfZQoaAV9lCiMB2NoZWNrZWSUSwCMCXVuY2hlY2tlZJRLAGg9SwB1aCd9lGgpj5QoaFRoVWg9kGgrTnVijA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCd9lGgpj5QoaDJoNmg1aEtoQGhZaE1oSWgzaExoWGhOaEpoNJBoK051YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwFzaCd9lGgpj5QoaGKQaCtOdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5RLD2hJXZSMCGZhaWx1cmVzlF2UaFhdlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMC21vcmVfY2xhaW1zlF2UjBRtb3JlX2NsYWltX2xvY2F0aW9uc5RdlIwObW9yZV9jaXRhdGlvbnOUXZSMB2ZhaWx1cmWUTowGY2xhaW1zlF2UaACMC1Jldmlld0NsYWltlJOUKYGUfZQoaAV9lCiMBWluZGV4lEsAjAVjbGFpbZSMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAlwb3NpdGlvbnOUTowGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKIwHdmVyZGljdJSMBFRydWWUaB6MBGhpZ2iUjAZzb3VyY2WUjAphc3Nlc3NtZW50lIwIaXNfaXNzdWWUiXVoJ32UaCmPlChoHmiEaIdoiZBoK051YowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRohIwEVHJ1ZZRoHowEaGlnaJSMCXJhdGlvbmFsZZROjAdkaXNzZW50lE6MEHZlcmlmaWNhdGlvbl91cmyUTowKZXJyb3JfY29kZZROjBFpZGVudGlmaWVkX2NsYWltc5RdlIwEaGludJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROaHJOdWgnfZRoKY+UKGibaJZol2geaAtohGiZaJVomGicaHKQaCtOdWKMCmVzY2FsYXRpb26UaACMCkVzY2FsYXRpb26Uk5QpgZR9lChoBX2UKIwNbWF0Y2hlZF9ydWxlc5RdlIwLZGlzcG9zaXRpb26UjAxub3Rfc2VsZWN0ZWSUdWgnfZRoKY+UKGinaKWQaCtOdWKMDHZlcmlmaWNhdGlvbpROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoJ32UaCmPlChoe2iMaJ9oemiraKxofmh9kGgrTnViYYwJY2l0YXRpb25zlF2UKGgAjA5SZXZpZXdDaXRhdGlvbpSTlCmBlH2UKGgFfZQoaHpLAIwJcmVmZXJlbmNllIwaYSByZXBvcnQgZnJvbSB0aGUgbWluaXN0cnmUjAljaXRlZF91cmyUjB9odHRwczovL2V4YW1wbGUuZ292L3JlcG9ydC0yMDI0lIwDZG9plE6MCXN0YXRlbWVudJROjAZxdW90ZXOUXZSMCHBvc2l0aW9ulE5ofk6MBWNoZWNrlGgAjBNSZXZpZXdDaXRhdGlvbkNoZWNrlJOUKYGUfZQoaAV9lChoC4wHcGVuZGluZ5SMCXBhZ2VfcmVhZJROjApwYWdlX3RpdGxllE6ME3BhZ2VfcHVibGlzaGVkX2RhdGWUTowNcGFnZV9sYW5ndWFnZZROjApzb3VyY2VfdXJslE6MDnNvdXJjZV92ZXJzaW9ulE6MB3N1cHBvcnSUTowHc25pcHBldJROaJVOjAVxdW90ZZROjA1taXNzaW5nX3F1b3RllE6MDmRvaV9yZWdpc3RlcmVklE6MCG1ldGFkYXRhlE6MFG1ldGFkYXRhX2RpZmZlcmVuY2VzlF2UjApyZWdpc3RlcmVklE6MEHVuY2hlY2tlZF9yZWFzb26UTmibTmhyTnVoJ32UaCmPlChoyGjVaJVoyWjKaJto0GjRaAtoz2jSaM5ox2jUaMxoxmjLaM1ocpBoK051YnVoJ32UaCmPlChou2h+aLZov2h6aLpovGi4aL6QaCtOdWJosimBlH2UKGgFfZQoaHpLAWi2jAthIHN0YXRlbWVudJRouIwdaHR0cHM6Ly9leGFtcGxlLm9yZy9zdGF0ZW1lbnSUaLpOaLtOaLxdlGi+Tmh+Tmi/aMEpgZR9lChoBX2UKGgLjAdwZW5kaW5nlGjGTmjHTmjITmjJTmjKTmjLTmjMTmjNTmiVTmjOTmjPTmjQTmjRTmjSXZRo1E5o1U5om05ock51aCd9lGgpj5QoaMho1WiVaMloymibaNBo0WgLaM9o0mjOaMdo1GjMaMZoy2jNaHKQaCtOdWJ1aCd9lGgpj5QoaLtofmi2aL9oemi6aLxouGi+kGgrTnViZXVoJ32UaCmPlChobGhnaBBoC2gTaGpoZWgsaHBoXGgOaFhoc2gNaG5oEWgJaK9oSWgHaHKQaCtOdWIu", + "review__get_citations_skipped_switched_off.json": "gASVwwcAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLFIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwGMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lEsUjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklIwMc3dpdGNoZWRfb2ZmlHVoKX2UaCuPlChoNGg4aDdoTWhCaFJoT2hLaDVoTmhRaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAXNoKX2UaCuPlChoXJBoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UjAdmYWlsdXJllE6MBmNsYWltc5RdlGgAjAtSZXZpZXdDbGFpbZSTlCmBlH2UKGgFfZQojAVpbmRleJRLAIwFY2xhaW2UjChUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulIwJcG9zaXRpb25zlE6MBnJlc3VsdJRoAIwMUmV2aWV3UmVzdWx0lJOUKYGUfZQoaAV9lCiMB3ZlcmRpY3SUjARUcnVllGggjARoaWdolIwGc291cmNllIwKYXNzZXNzbWVudJSMCGlzX2lzc3VllIl1aCl9lGgrj5QoaCBofmiBaIOQaC1OdWKMCmFzc2Vzc21lbnSUaACMEFJldmlld0Fzc2Vzc21lbnSUk5QpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaH6MBFRydWWUaCCMBGhpZ2iUjAlyYXRpb25hbGWUTowHZGlzc2VudJROjBB2ZXJpZmljYXRpb25fdXJslE6MCmVycm9yX2NvZGWUTowRaWRlbnRpZmllZF9jbGFpbXOUXZSMBGhpbnSUTowRc3VnZ2VzdGVkX3Jld3JpdGWUTmhsTnVoKX2UaCuPlCholWiQaJFoIGgLaH5ok2iPaJJolmhskGgtTnVijAplc2NhbGF0aW9ulGgAjApFc2NhbGF0aW9ulJOUKYGUfZQoaAV9lCiMDW1hdGNoZWRfcnVsZXOUXZSMC2Rpc3Bvc2l0aW9ulIwMbm90X3NlbGVjdGVklHVoKX2UaCuPlChooWifkGgtTnVijAx2ZXJpZmljYXRpb26UTowPc3VnZ2VzdGVkX2VkaXRzlE51aCl9lGgrj5QoaHVohmiZaHRopWimaHhod5BoLU51YmGMCWNpdGF0aW9uc5RdlHVoKX2UaCuPlChoZmhhaBFoC2gVaGRoX2guaGpoVmgPaFFobWgNaGhoE2gJaKloS2gHaGyQaC1OdWIu", + "review__get_citations_skipped_url_input.json": "gASVeAUAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwGZmFpbGVklIwHb3V0Y29tZZSMCXVuY2hlY2tlZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjAhsYW5ndWFnZZSMAmVulIwGcG9saWN5lGgAjBBFc2NhbGF0aW9uUG9saWN5lJOUKYGUfZQoaAV9lCiMCHZlcmRpY3RzlF2UKIwFRmFsc2WUjAxNb3N0bHkgRmFsc2WUjAVNaXhlZJRljApjb25maWRlbmNllF2UjANsb3eUYYwPbWF4X2Fzc2Vzc21lbnRzlEsUjBFtYXhfdmVyaWZpY2F0aW9uc5RLBYwFZGVwdGiUjAhzdGFuZGFyZJSMDW1heF9jaXRhdGlvbnOUSxSMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoJWggaCdoKGgkaCOQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklE6MC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklE6MD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5ROjA12ZXJpZmljYXRpb25zlE6MBmlzc3Vlc5RLAIwPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJRLFIwWY2l0YXRpb25fbGltaXRfcmVhY2hlZJROjA9jaXRhdGlvbl9jaGVja3OUTowPY2l0YXRpb25faXNzdWVzlEsAjBFjaXRhdGlvbnNfc2tpcHBlZJSMCXVybF9pbnB1dJR1aCl9lGgrj5QoaDRoOGg3aDxoOWhBaD5oOmg1aD1oQGg/aDtoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwBzaCl9lGgrj5QoaEuQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaDpdlIwIZmFpbHVyZXOUXZRoQF2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUTowUbW9yZV9jbGFpbV9sb2NhdGlvbnOUTowObW9yZV9jaXRhdGlvbnOUTowHZmFpbHVyZZRoAIwMRmFpbHVyZUJsb2NrlJOUKYGUfZQoaAV9lCiMDmZhaWx1cmVfcmVhc29ulIwUdXBzdHJlYW1fdW5hdmFpbGFibGWUjA1mYWlsdXJlX2NsYXNzlIwUdXBzdHJlYW1fdW5hdmFpbGFibGWUjAlyZXRyeWFibGWUiIwEaGludJROjAhkb2NzX3VybJSMMGh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyN1cHN0cmVhbS11bmF2YWlsYWJsZZR1aCl9lGgrj5QoaGNoXmhkaGBoYpBoLU51YowGY2xhaW1zlF2UjAljaXRhdGlvbnOUXZR1aCl9lGgrj5QoaFVoUGgRaAtoFWhTaE5oLmhXaEVoD2hAaGhoDWhWaBNoCWhqaDpoB2hYkGgtTnViLg==", + "review__get_claim_limit_not_reached.json": "gASVBwkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSwOMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwKMC2NsYWltX2xpbWl0lEsDjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwKMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKX2UaCuPlChoNGg4aDdoTWhCaFJoT2hLaDVoTmhRaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoKX2UaCuPlChoW5BoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UjAdmYWlsdXJllE6MBmNsYWltc5RdlChoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUaACMDFJldmlld1Jlc3VsdJSTlCmBlH2UKGgFfZQojAd2ZXJkaWN0lIwEVHJ1ZZRoIIwEaGlnaJSMBnNvdXJjZZSMCmFzc2Vzc21lbnSUjAhpc19pc3N1ZZSJdWgpfZRoK4+UKGggaH1ogGiCkGgtTnVijAphc3Nlc3NtZW50lGgAjBBSZXZpZXdBc3Nlc3NtZW50lJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGh9jARUcnVllGggjARoaWdolIwJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowQdmVyaWZpY2F0aW9uX3VybJROjAplcnJvcl9jb2RllE6MEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE5oa051aCl9lGgrj5QoaJRoj2iQaCBoC2h9aJJojmiRaJVoa5BoLU51YowKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAtkaXNwb3NpdGlvbpSMDG5vdF9zZWxlY3RlZJR1aCl9lGgrj5QoaKBonpBoLU51YowMdmVyaWZpY2F0aW9ulE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGh0aIVomGhzaKRopWh3aHaQaC1OdWJobymBlH2UKGgFfZQoaHNLAWh0jCJXYXRlciBib2lscyBhdCAxMDAgQyBhdCBzZWEgbGV2ZWwulGh2Tmh3aHkpgZR9lChoBX2UKGh9jARUcnVllGggjARoaWdolGiAjAphc3Nlc3NtZW50lGiCiXVoKX2UaCuPlChoIGh9aIBogpBoLU51YmiFaIcpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaH2MBFRydWWUaCCMBGhpZ2iUaI5OaI9OaJBOaJFOaJJdlGiUTmiVTmhrTnVoKX2UaCuPlCholGiPaJBoIGgLaH1okmiOaJFolWhrkGgtTnViaJhomimBlH2UKGgFfZQoaJ5dlGigjAxub3Rfc2VsZWN0ZWSUdWgpfZRoK4+UKGigaJ6QaC1OdWJopE5opU51aCl9lGgrj5QoaHRohWiYaHNopGilaHdodpBoLU51YmWMCWNpdGF0aW9uc5RdlHVoKX2UaCuPlChoZWhgaBFoC2gVaGNoXmguaGloVWgPaFFobGgNaGdoE2gJaMZoS2gHaGuQaC1OdWIu", + "review__get_claim_limit_reached_exact.json": "gASVBwkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSwKMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwKMC2NsYWltX2xpbWl0lEsCjBNjbGFpbV9saW1pdF9yZWFjaGVklIiMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwKMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKX2UaCuPlChoNGg4aDdoTWhCaFJoT2hLaDVoTmhRaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoKX2UaCuPlChoW5BoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UjAdmYWlsdXJllE6MBmNsYWltc5RdlChoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUaACMDFJldmlld1Jlc3VsdJSTlCmBlH2UKGgFfZQojAd2ZXJkaWN0lIwEVHJ1ZZRoIIwEaGlnaJSMBnNvdXJjZZSMCmFzc2Vzc21lbnSUjAhpc19pc3N1ZZSJdWgpfZRoK4+UKGggaH1ogGiCkGgtTnVijAphc3Nlc3NtZW50lGgAjBBSZXZpZXdBc3Nlc3NtZW50lJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGh9jARUcnVllGggjARoaWdolIwJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowQdmVyaWZpY2F0aW9uX3VybJROjAplcnJvcl9jb2RllE6MEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE5oa051aCl9lGgrj5QoaJRoj2iQaCBoC2h9aJJojmiRaJVoa5BoLU51YowKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAtkaXNwb3NpdGlvbpSMDG5vdF9zZWxlY3RlZJR1aCl9lGgrj5QoaKBonpBoLU51YowMdmVyaWZpY2F0aW9ulE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGh0aIVomGhzaKRopWh3aHaQaC1OdWJobymBlH2UKGgFfZQoaHNLAWh0jCJXYXRlciBib2lscyBhdCAxMDAgQyBhdCBzZWEgbGV2ZWwulGh2Tmh3aHkpgZR9lChoBX2UKGh9jARUcnVllGggjARoaWdolGiAjAphc3Nlc3NtZW50lGiCiXVoKX2UaCuPlChoIGh9aIBogpBoLU51YmiFaIcpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaH2MBFRydWWUaCCMBGhpZ2iUaI5OaI9OaJBOaJFOaJJdlGiUTmiVTmhrTnVoKX2UaCuPlCholGiPaJBoIGgLaH1okmiOaJFolWhrkGgtTnViaJhomimBlH2UKGgFfZQoaJ5dlGigjAxub3Rfc2VsZWN0ZWSUdWgpfZRoK4+UKGigaJ6QaC1OdWJopE5opU51aCl9lGgrj5QoaHRohWiYaHNopGilaHdodpBoLU51YmWMCWNpdGF0aW9uc5RdlHVoKX2UaCuPlChoZWhgaBFoC2gVaGNoXmguaGloVWgPaFFobGgNaGdoE2gJaMZoS2gHaGuQaC1OdWIu", + "review__get_completed_assess_only.json": "gASVTAoAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMDGlzc3Vlc19mb3VuZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjAhsYW5ndWFnZZSMAmVulIwGcG9saWN5lGgAjBBFc2NhbGF0aW9uUG9saWN5lJOUKYGUfZQoaAV9lCiMCHZlcmRpY3RzlF2UKIwFRmFsc2WUjAxNb3N0bHkgRmFsc2WUjAVNaXhlZJRljApjb25maWRlbmNllF2UjANsb3eUYYwPbWF4X2Fzc2Vzc21lbnRzlEsUjBFtYXhfdmVyaWZpY2F0aW9uc5RLAIwFZGVwdGiUjAhzdGFuZGFyZJSMDW1heF9jaXRhdGlvbnOUSwCMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoJWggaCdoKGgkaCOQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklEsCjAtjbGFpbV9saW1pdJRLFIwTY2xhaW1fbGltaXRfcmVhY2hlZJSJjA9pbnB1dF90cnVuY2F0ZWSUiYwLYXNzZXNzbWVudHOUaACMFlJldmlld0Fzc2Vzc21lbnRDb3VudHOUk5QpgZR9lChoBX2UKIwJY29tcGxldGVklEsCjAZmYWlsZWSUSwB1aCl9lGgrj5QoaD5oP5BoLU51YowNdmVyaWZpY2F0aW9uc5RoAIwYUmV2aWV3VmVyaWZpY2F0aW9uQ291bnRzlJOUKYGUfZQoaAV9lCiMB3BsYW5uZWSUSwBoPksAaD9LAHVoKX2UaCuPlChoPmg/aEiQaC1OdWKMBmlzc3Vlc5RLAYwPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJROjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhSaE9oS2g1aE5oUWhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwJzaCl9lGgrj5QoaFuQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlGgAjAtSZXZpZXdJc3N1ZZSTlCmBlH2UKGgFfZQojAtjbGFpbV9pbmRleJRLAYwFY2xhaW2UjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjA52ZXJpZmllZF9jbGFpbZROjAd2ZXJkaWN0lIwFRmFsc2WUaCCMBGhpZ2iUjAZzb3VyY2WUjAphc3Nlc3NtZW50lIwPdmVyaWZpY2F0aW9uX2lklE6ME3ZlcmlmaWNhdGlvbl9zdGF0dXOUTowQdmVyaWZpY2F0aW9uX3VybJROjAN1cmyUTowKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAd2ZXJkaWN0lGGMC2Rpc3Bvc2l0aW9ulIwDY2FwlHVoKX2UaCuPlChoe2h4kGgtTnVijAtrZXlfZmluZGluZ5ROjAlyYXRpb25hbGWUTowRc3VnZ2VzdGVkX3Jld3JpdGWUTowHZmFpbHVyZZROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoKX2UaCuPlChoZmhuaHBoIGhpaG9ocmiAaINocWhsaGhoZWh/aIFogpBoLU51YmGMCGZhaWx1cmVzlF2UaFFdlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMC21vcmVfY2xhaW1zlF2UjBRtb3JlX2NsYWltX2xvY2F0aW9uc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRogk6MBmNsYWltc5RdlChoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwBoZowoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUaACMDFJldmlld1Jlc3VsdJSTlCmBlH2UKGgFfZQoaGmMBFRydWWUaCCMBGhpZ2iUaGyMCmFzc2Vzc21lbnSUjAhpc19pc3N1ZZSJdWgpfZRoK4+UKGggaGlobGikkGgtTnVijAphc3Nlc3NtZW50lGgAjBBSZXZpZXdBc3Nlc3NtZW50lJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGhpjARUcnVllGggjARoaWdolGiATowHZGlzc2VudJROaHBOjAplcnJvcl9jb2RllE6MEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE5ogU5ogk51aCl9lGgrj5QoaLRosGhwaCBoC2hpaLJogGixaIFogpBoLU51YmhyaHQpgZR9lChoBX2UKGh4XZRoe4wMbm90X3NlbGVjdGVklHVoKX2UaCuPlChoe2h4kGgtTnVijAx2ZXJpZmljYXRpb26UTmiDTnVoKX2UaCuPlChoZminaHJomGi+aINom2iakGgtTnViaJQpgZR9lChoBX2UKGiYSwFoZoweVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulGiaTmibaJ0pgZR9lChoBX2UKGhpjAVGYWxzZZRoIIwEaGlnaJRobIwKYXNzZXNzbWVudJRopIh1aCl9lGgrj5QoaCBoaWhsaKSQaC1OdWJop2ipKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGhpjAVGYWxzZZRoIIwEaGlnaJRogE5osE5ocE5osU5osl2UaLROaIFOaIJOdWgpfZRoK4+UKGi0aLBocGggaAtoaWiyaIBosWiBaIKQaC1OdWJocmh0KYGUfZQoaAV9lChoeF2UjAd2ZXJkaWN0lGFoe4wDY2FwlHVoKX2UaCuPlChoe2h4kGgtTnViaL5OaINOdWgpfZRoK4+UKGhmaKdocmiYaL5og2ibaJqQaC1OdWJljAljaXRhdGlvbnOUXZR1aCl9lGgrj5QoaItohmgRaAtoFWiJaF5oLmiPaFVoD2hRaJFoDWiNaBNoCWjgaEtoB2iCkGgtTnViLg==", + "review__get_completed_clean.json": "gASVBAkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwKMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwKMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKX2UaCuPlChoNGg4aDdoTWhCaFJoT2hLaDVoTmhRaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoKX2UaCuPlChoW5BoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UjAdmYWlsdXJllE6MBmNsYWltc5RdlChoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUaACMDFJldmlld1Jlc3VsdJSTlCmBlH2UKGgFfZQojAd2ZXJkaWN0lIwEVHJ1ZZRoIIwEaGlnaJSMBnNvdXJjZZSMCmFzc2Vzc21lbnSUjAhpc19pc3N1ZZSJdWgpfZRoK4+UKGggaH1ogGiCkGgtTnVijAphc3Nlc3NtZW50lGgAjBBSZXZpZXdBc3Nlc3NtZW50lJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGh9jARUcnVllGggjARoaWdolIwJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowQdmVyaWZpY2F0aW9uX3VybJROjAplcnJvcl9jb2RllE6MEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE5oa051aCl9lGgrj5QoaJRoj2iQaCBoC2h9aJJojmiRaJVoa5BoLU51YowKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAtkaXNwb3NpdGlvbpSMDG5vdF9zZWxlY3RlZJR1aCl9lGgrj5QoaKBonpBoLU51YowMdmVyaWZpY2F0aW9ulE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGh0aIVomGhzaKRopWh3aHaQaC1OdWJobymBlH2UKGgFfZQoaHNLAWh0jB9QYXJpcyBpcyB0aGUgY2FwaXRhbCBvZiBGcmFuY2UulGh2Tmh3aHkpgZR9lChoBX2UKGh9jARUcnVllGggjARoaWdolGiAjAphc3Nlc3NtZW50lGiCiXVoKX2UaCuPlChoIGh9aIBogpBoLU51YmiFaIcpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaH2MBFRydWWUaCCMBGhpZ2iUaI5OaI9OaJBOaJFOaJJdlGiUTmiVTmhrTnVoKX2UaCuPlCholGiPaJBoIGgLaH1okmiOaJFolWhrkGgtTnViaJhomimBlH2UKGgFfZQoaJ5dlGigjAxub3Rfc2VsZWN0ZWSUdWgpfZRoK4+UKGigaJ6QaC1OdWJopE5opU51aCl9lGgrj5QoaHRohWiYaHNopGilaHdodpBoLU51YmWMCWNpdGF0aW9uc5RdlHVoKX2UaCuPlChoZWhgaBFoC2gVaGNoXmguaGloVWgPaFFobGgNaGdoE2gJaMZoS2gHaGuQaC1OdWIu", + "review__get_completed_issues_all_verified.json": "gASVIhMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMDGlzc3Vlc19mb3VuZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjAhsYW5ndWFnZZSMAmVulIwGcG9saWN5lGgAjBBFc2NhbGF0aW9uUG9saWN5lJOUKYGUfZQoaAV9lCiMCHZlcmRpY3RzlF2UKIwFRmFsc2WUjAxNb3N0bHkgRmFsc2WUjAVNaXhlZJRljApjb25maWRlbmNllF2UjANsb3eUYYwPbWF4X2Fzc2Vzc21lbnRzlEsUjBFtYXhfdmVyaWZpY2F0aW9uc5RLBYwFZGVwdGiUjAhzdGFuZGFyZJSMDW1heF9jaXRhdGlvbnOUSwCMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoJWggaCdoKGgkaCOQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklEsDjAtjbGFpbV9saW1pdJRLFIwTY2xhaW1fbGltaXRfcmVhY2hlZJSJjA9pbnB1dF90cnVuY2F0ZWSUiYwLYXNzZXNzbWVudHOUaACMFlJldmlld0Fzc2Vzc21lbnRDb3VudHOUk5QpgZR9lChoBX2UKIwJY29tcGxldGVklEsDjAZmYWlsZWSUSwB1aCl9lGgrj5QoaD5oP5BoLU51YowNdmVyaWZpY2F0aW9uc5RoAIwYUmV2aWV3VmVyaWZpY2F0aW9uQ291bnRzlJOUKYGUfZQoaAV9lCiMB3BsYW5uZWSUSwJoPksCaD9LAHVoKX2UaCuPlChoPmg/aEiQaC1OdWKMBmlzc3Vlc5RLAowPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJROjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhSaE9oS2g1aE5oUWhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSxdzaCl9lGgrj5QoaFuQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlChoAIwLUmV2aWV3SXNzdWWUk5QpgZR9lChoBX2UKIwLY2xhaW1faW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMDnZlcmlmaWVkX2NsYWltlE6MB3ZlcmRpY3SUjAVGYWxzZZRoIIwEaGlnaJSMBnNvdXJjZZSMDHZlcmlmaWNhdGlvbpSMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwTdmVyaWZpY2F0aW9uX3N0YXR1c5SMCWNvbXBsZXRlZJSMEHZlcmlmaWNhdGlvbl91cmyUjC1odHRwczovL2xlbnouaW8vYXBpL3YxL3ZlcmlmaWNhdGlvbnMvNjhjYTRhYWaUjAN1cmyUjC1odHRwczovL2xlbnouaW8vYy90aGUtZWFydGgtaXMtcm91bmQtNjhjYTRhYWaUjAplc2NhbGF0aW9ulGgAjApFc2NhbGF0aW9ulJOUKYGUfZQoaAV9lCiMDW1hdGNoZWRfcnVsZXOUXZSMB3ZlcmRpY3SUYYwLZGlzcG9zaXRpb26UjAdwbGFubmVklHVoKX2UaCuPlChof2h8kGgtTnVijAtrZXlfZmluZGluZ5SMNEZpbmRpbmcgZm9yIFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAlyYXRpb25hbGWUTowRc3VnZ2VzdGVkX3Jld3JpdGWUjC9GaXhlZDogVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMB2ZhaWx1cmWUTowPc3VnZ2VzdGVkX2VkaXRzlE51aCl9lGgrj5QoaGZobmhyaCBoaWhwaHZohWiJaHRobGhoaGVog2iGaIiQaC1OdWJoYSmBlH2UKGgFfZQoaGVLAWhmjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UaGhOaGmMBUZhbHNllGggjARoaWdolGhsjAx2ZXJpZmljYXRpb26UaG6MCDRkNDRkZmFmlGhwjAljb21wbGV0ZWSUaHKMLWh0dHBzOi8vbGVuei5pby9hcGkvdjEvdmVyaWZpY2F0aW9ucy80ZDQ0ZGZhZpRodIwtaHR0cHM6Ly9sZW56LmlvL2MvdGhlLWVhcnRoLWlzLXJvdW5kLTRkNDRkZmFmlGh2aHgpgZR9lChoBX2UKGh8XZSMB3ZlcmRpY3SUYWh/jAdwbGFubmVklHVoKX2UaCuPlChof2h8kGgtTnViaIOMKkZpbmRpbmcgZm9yIFRoZSBFaWZmZWwgVG93ZXIgaXMgaW4gQmVybGluLpRohU5ohowlRml4ZWQ6IFRoZSBFaWZmZWwgVG93ZXIgaXMgaW4gQmVybGluLpRoiE5oiU51aCl9lGgrj5QoaGZobmhyaCBoaWhwaHZohWiJaHRobGhoaGVog2iGaIiQaC1OdWJljAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UaIhOjAZjbGFpbXOUXZQoaACMC1Jldmlld0NsYWltlJOUKYGUfZQoaAV9lCiMBWluZGV4lEsAaGaMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAlwb3NpdGlvbnOUTowGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKGhpjAVGYWxzZZRoIIwEaGlnaJRobIwMdmVyaWZpY2F0aW9ulIwIaXNfaXNzdWWUiHVoKX2UaCuPlChoIGhpaGxowZBoLU51YowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRoaYwMTW9zdGx5IEZhbHNllGggjAZtZWRpdW2UaIVOjAdkaXNzZW50lE5ock6MCmVycm9yX2NvZGWUTowRaWRlbnRpZmllZF9jbGFpbXOUXZSMBGhpbnSUTmiGTmiITnVoKX2UaCuPlCho0WjNaHJoIGgLaGloz2iFaM5ohmiIkGgtTnViaHZoeCmBlH2UKGgFfZQoaHxdlIwHdmVyZGljdJRhaH+MB3BsYW5uZWSUdWgpfZRoK4+UKGh/aHyQaC1OdWKMDHZlcmlmaWNhdGlvbpRoAIwSUmV2aWV3VmVyaWZpY2F0aW9ulJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklIwOY29udGVudF9zdGF0dXOUjAlhdmFpbGFibGWUaG6MCDY4Y2E0YWFmlIwHdGFza19pZJSMIDdjZmYxOGRhMmQ5NzlkNjM3MGU1NGExNjBiZTEyMWFklGhmjChUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulGgTjAJlbpSMCnZpc2liaWxpdHmUjAdwcml2YXRllGgljAhzdGFuZGFyZJSMBmRvbWFpbpSMAJSMCGVudGl0aWVzlF2UaGmMBUZhbHNllGggjARoaWdolIwKbGVuel9zY29yZZRLAmiDjDRGaW5kaW5nIGZvciBUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulIwRZXhlY3V0aXZlX3N1bW1hcnmUjDRTdW1tYXJ5IGZvciBUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulGiGjC9GaXhlZDogVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCHdhcm5pbmdzlF2UjAJ3MZRhaA+MIDIwMjYtMTAtMDFUMDk6MTQ6MDAuMTIzNDU2KzAwOjAwlIwLbW9kaWZpZWRfYXSUTmhyjC1odHRwczovL2xlbnouaW8vYXBpL3YxL3ZlcmlmaWNhdGlvbnMvNjhjYTRhYWaUaHSMLWh0dHBzOi8vbGVuei5pby9jL3RoZS1lYXJ0aC1pcy1yb3VuZC02OGNhNGFhZpRoiE51aCl9lGgrj5QoaG5ocmjvaCBo/Gj1aHRo6mgLaO1og2hmaCVoD2hpaIZo+GjmaBNo82jjaIiQaC1OdWJoiU51aCl9lGgrj5QoaGZoxGh2aLVo3GiJaLhot5BoLU51YmixKYGUfZQoaAV9lChotUsBaGaMHlRoZSBFaWZmZWwgVG93ZXIgaXMgaW4gQmVybGluLpRot05ouGi6KYGUfZQoaAV9lChoaYwFRmFsc2WUaCCMBGhpZ2iUaGyMDHZlcmlmaWNhdGlvbpRowYh1aCl9lGgrj5QoaCBoaWhsaMGQaC1OdWJoxGjGKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGhpjAVGYWxzZZRoIIwEaGlnaJRohU5ozU5ock5ozk5oz12UaNFOaIZOaIhOdWgpfZRoK4+UKGjRaM1ocmggaAtoaWjPaIVozmiGaIiQaC1OdWJodmh4KYGUfZQoaAV9lChofF2UjAd2ZXJkaWN0lGFof4wHcGxhbm5lZJR1aCl9lGgrj5QoaH9ofJBoLU51YmjcaN4pgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaOOMCWF2YWlsYWJsZZRobowINGQ0NGRmYWaUaOaMIDBiOTJiNDQzZWI2OWI5YzcxNDM0ZmRjNjRmMmNhOGJllGhmjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UaBOMAmVulGjqjAdwcml2YXRllGgljAhzdGFuZGFyZJRo7WjuaO9dlGhpjAVGYWxzZZRoIIwEaGlnaJRo80sCaIOMKkZpbmRpbmcgZm9yIFRoZSBFaWZmZWwgVG93ZXIgaXMgaW4gQmVybGluLpRo9YwqU3VtbWFyeSBmb3IgVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulGiGjCVGaXhlZDogVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulGj4XZSMAncxlGFoD4wgMjAyNi0xMC0wMVQwOToxNDowMC4xMjM0NTYrMDA6MDCUaPxOaHKMLWh0dHBzOi8vbGVuei5pby9hcGkvdjEvdmVyaWZpY2F0aW9ucy80ZDQ0ZGZhZpRodIwtaHR0cHM6Ly9sZW56LmlvL2MvdGhlLWVhcnRoLWlzLXJvdW5kLTRkNDRkZmFmlGiITnVoKX2UaCuPlChobmhyaO9oIGj8aPVodGjqaAto7WiDaGZoJWgPaGlohmj4aOZoE2jzaONoiJBoLU51YmiJTnVoKX2UaCuPlChoZmjEaHZotWjcaIlouGi3kGgtTnViaLEpgZR9lChoBX2UKGi1SwJoZowfUGFyaXMgaXMgdGhlIGNhcGl0YWwgb2YgRnJhbmNlLpRot05ouGi6KYGUfZQoaAV9lChoaYwEVHJ1ZZRoIIwEaGlnaJRobIwKYXNzZXNzbWVudJRowYl1aCl9lGgrj5QoaCBoaWhsaMGQaC1OdWJoxGjGKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGhpjARUcnVllGggjARoaWdolGiFTmjNTmhyTmjOTmjPXZRo0U5ohk5oiE51aCl9lGgrj5QoaNFozWhyaCBoC2hpaM9ohWjOaIZoiJBoLU51Ymh2aHgpgZR9lChoBX2UKGh8XZRof4wMbm90X3NlbGVjdGVklHVoKX2UaCuPlChof2h8kGgtTnViaNxOaIlOdWgpfZRoK4+UKGhmaMRodmi1aNxoiWi4aLeQaC1OdWJljAljaXRhdGlvbnOUXZR1aCl9lGgrj5QoaKhoo2gRaAtoFWimaF5oLmisaFVoD2hRaK5oDWiqaBNoCWpYAQAAaEtoB2iIkGgtTnViLg==", + "review__get_completed_issues_full.json": "gASVyhUAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMCmluY29tcGxldGWUjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lIwbMjAyNi0xMC0wMVQxMDowNzowMC4xMjM0NTZalIwIbGFuZ3VhZ2WUjAJlbpSMBnBvbGljeZRoAIwQRXNjYWxhdGlvblBvbGljeZSTlCmBlH2UKGgFfZQojAh2ZXJkaWN0c5RdlCiMBUZhbHNllIwMTW9zdGx5IEZhbHNllIwFTWl4ZWSUZYwKY29uZmlkZW5jZZRdlIwDbG93lGGMD21heF9hc3Nlc3NtZW50c5RLFIwRbWF4X3ZlcmlmaWNhdGlvbnOUSwWMBWRlcHRolIwIc3RhbmRhcmSUjA1tYXhfY2l0YXRpb25zlEsAjA1zdWdnZXN0X2VkaXRzlIl1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgbaCVoIGgnaChoJGgjkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjA1SZXZpZXdTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NsYWltc19zZWxlY3RlZJRLBIwLY2xhaW1fbGltaXSUSxSME2NsYWltX2xpbWl0X3JlYWNoZWSUiYwPaW5wdXRfdHJ1bmNhdGVklImMC2Fzc2Vzc21lbnRzlGgAjBZSZXZpZXdBc3Nlc3NtZW50Q291bnRzlJOUKYGUfZQoaAV9lCiMCWNvbXBsZXRlZJRLA4wGZmFpbGVklEsBdWgpfZRoK4+UKGg+aD+QaC1OdWKMDXZlcmlmaWNhdGlvbnOUaACMGFJldmlld1ZlcmlmaWNhdGlvbkNvdW50c5STlCmBlH2UKGgFfZQojAdwbGFubmVklEsCaD5LAWg/SwF1aCl9lGgrj5QoaD5oP2hIkGgtTnVijAZpc3N1ZXOUSwKMD2NpdGF0aW9uc19mb3VuZJROjBJjaXRhdGlvbnNfc2VsZWN0ZWSUTowOY2l0YXRpb25fbGltaXSUTowWY2l0YXRpb25fbGltaXRfcmVhY2hlZJROjA9jaXRhdGlvbl9jaGVja3OUTowPY2l0YXRpb25faXNzdWVzlEsAjBFjaXRhdGlvbnNfc2tpcHBlZJROdWgpfZRoK4+UKGg0aDhoN2hNaEJoUmhPaEtoNWhOaFFoUGhMaDaQaC1OdWKMB2NyZWRpdHOUaACMDVJldmlld0NyZWRpdHOUk5QpgZR9lChoBX2UjAdjaGFyZ2VklEsNc2gpfZRoK4+UKGhbkGgtTnVijBJwb2xsX2FmdGVyX3NlY29uZHOUTmhLXZQoaACMC1Jldmlld0lzc3VllJOUKYGUfZQoaAV9lCiMC2NsYWltX2luZGV4lEsAjAVjbGFpbZSMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjA52ZXJpZmllZF9jbGFpbZROjAd2ZXJkaWN0lIwFRmFsc2WUaCCMBGhpZ2iUjAZzb3VyY2WUjAx2ZXJpZmljYXRpb26UjA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSME3ZlcmlmaWNhdGlvbl9zdGF0dXOUjAljb21wbGV0ZWSUjBB2ZXJpZmljYXRpb25fdXJslIwtaHR0cHM6Ly9sZW56LmlvL2FwaS92MS92ZXJpZmljYXRpb25zLzY4Y2E0YWFmlIwDdXJslIwtaHR0cHM6Ly9sZW56LmlvL2MvdGhlLWVhcnRoLWlzLXJvdW5kLTY4Y2E0YWFmlIwKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAd2ZXJkaWN0lGGMC2Rpc3Bvc2l0aW9ulIwHcGxhbm5lZJR1aCl9lGgrj5QoaH9ofJBoLU51YowLa2V5X2ZpbmRpbmeUjDRGaW5kaW5nIGZvciBUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulIwJcmF0aW9uYWxllE6MEXN1Z2dlc3RlZF9yZXdyaXRllIwvRml4ZWQ6IFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAdmYWlsdXJllE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGhmaG5ocmggaGlocGh2aIVoiWh0aGxoaGhlaINohmiIkGgtTnViaGEpgZR9lChoBX2UKGhlSwJoZoweVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulGhoTmhpjAVGYWxzZZRoIIwEaGlnaJRobIwKYXNzZXNzbWVudJRobk5ocIwGZmFpbGVklGhyTmh0Tmh2aHgpgZR9lChoBX2UKGh8XZSMB3ZlcmRpY3SUYWh/jAdwbGFubmVklHVoKX2UaCuPlChof2h8kGgtTnViaINOaIVOaIZOaIhoAIwMRmFpbHVyZUJsb2NrlJOUKYGUfZQoaAV9lCiMDmZhaWx1cmVfcmVhc29ulIwOcmVzZWFyY2hfZW1wdHmUjA1mYWlsdXJlX2NsYXNzlIwVaW5zdWZmaWNpZW50X2V2aWRlbmNllIwJcmV0cnlhYmxllImMBGhpbnSUTowIZG9jc191cmyUjDFodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjaW5zdWZmaWNpZW50LWV2aWRlbmNllHVoKX2UaCuPlChopmihaKdoo2ilkGgtTnViaIlOdWgpfZRoK4+UKGhmaG5ocmggaGlocGh2aIVoiWh0aGxoaGhlaINohmiIkGgtTnViZYwIZmFpbHVyZXOUXZRoAIwNUmV2aWV3RmFpbHVyZZSTlCmBlH2UKGgFfZQoaGVLAWhmjCJXYXRlciBib2lscyBhdCAxMDAgQyBhdCBzZWEgbGV2ZWwulIwFc3RhZ2WUjAphc3Nlc3NtZW50lGiIaJ0pgZR9lChoBX2UKGihjBR1cHN0cmVhbV91bmF2YWlsYWJsZZRoo4wUdXBzdHJlYW1fdW5hdmFpbGFibGWUaKWIaKaMTkEgbW9kZWwgcHJvdmlkZXIgd2FzIHVuYXZhaWxhYmxlIGZvciB0aGlzIGl0ZW0uIFJldHJ5IGl0OyBub3RoaW5nIHdhcyBjaGFyZ2VkLpRop4wwaHR0cHM6Ly9sZW56LmlvL2RvY3MvZXJyb3JzI3Vwc3RyZWFtLXVuYXZhaWxhYmxllHVoKX2UaCuPlChopmihaKdoo2ilkGgtTnVidWgpfZRoK4+UKGhmaGVotWiIkGgtTnViYWhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UaIhOjAZjbGFpbXOUXZQoaACMC1Jldmlld0NsYWltlJOUKYGUfZQoaAV9lCiMBWluZGV4lEsAaGaMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAlwb3NpdGlvbnOUTowGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKGhpjAVGYWxzZZRoIIwEaGlnaJRobIwMdmVyaWZpY2F0aW9ulIwIaXNfaXNzdWWUiHVoKX2UaCuPlChoIGhpaGxo3pBoLU51YowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRoaYwMTW9zdGx5IEZhbHNllGggjAZtZWRpdW2UaIVOjAdkaXNzZW50lE5ock6MCmVycm9yX2NvZGWUTowRaWRlbnRpZmllZF9jbGFpbXOUXZRopk5ohk5oiE51aCl9lGgrj5QoaKZo6mhyaCBoC2hpaOxohWjraIZoiJBoLU51Ymh2aHgpgZR9lChoBX2UKGh8XZSMB3ZlcmRpY3SUYWh/jAdwbGFubmVklHVoKX2UaCuPlChof2h8kGgtTnVijAx2ZXJpZmljYXRpb26UaACMElJldmlld1ZlcmlmaWNhdGlvbpSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJSMDmNvbnRlbnRfc3RhdHVzlIwJYXZhaWxhYmxllGhujAg2OGNhNGFhZpSMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJRoZowoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpRoE4wCZW6UjAp2aXNpYmlsaXR5lIwHcHJpdmF0ZZRoJYwIc3RhbmRhcmSUjAZkb21haW6UjACUjAhlbnRpdGllc5RdlGhpjAVGYWxzZZRoIIwEaGlnaJSMCmxlbnpfc2NvcmWUSwJog4w0RmluZGluZyBmb3IgVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMEWV4ZWN1dGl2ZV9zdW1tYXJ5lIw0U3VtbWFyeSBmb3IgVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpRohowvRml4ZWQ6IFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAh3YXJuaW5nc5RdlIwCdzGUYWgPjCAyMDI2LTEwLTAxVDA5OjE0OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE5ocowtaHR0cHM6Ly9sZW56LmlvL2FwaS92MS92ZXJpZmljYXRpb25zLzY4Y2E0YWFmlGh0jC1odHRwczovL2xlbnouaW8vYy90aGUtZWFydGgtaXMtcm91bmQtNjhjYTRhYWaUaIhOdWgpfZRoK4+UKGhuaHJqCwEAAGggahgBAABqEQEAAGh0agYBAABoC2oJAQAAaINoZmglaA9oaWiGahQBAABqAgEAAGgTag8BAABo/2iIkGgtTnViaIlOdWgpfZRoK4+UKGhmaOFodmjSaPhoiWjVaNSQaC1OdWJozimBlH2UKGgFfZQoaNJLAWhmjCJXYXRlciBib2lscyBhdCAxMDAgQyBhdCBzZWEgbGV2ZWwulGjUTmjVTmjhaOMpgZR9lChoBX2UKGgLjAZmYWlsZWSUaGlOaCBOaIVOaOpOaHJOaOuMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGjsXZRopk5ohk5oiGidKYGUfZQoaAV9lChooYwUdXBzdHJlYW1fdW5hdmFpbGFibGWUaKOMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGiliGimjE5BIG1vZGVsIHByb3ZpZGVyIHdhcyB1bmF2YWlsYWJsZSBmb3IgdGhpcyBpdGVtLiBSZXRyeSBpdDsgbm90aGluZyB3YXMgY2hhcmdlZC6UaKeMMGh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyN1cHN0cmVhbS11bmF2YWlsYWJsZZR1aCl9lGgrj5QoaKZooWinaKNopZBoLU51YnVoKX2UaCuPlChopmjqaHJoIGgLaGlo7GiFaOtohmiIkGgtTnViaHZOaPhOaIlOdWgpfZRoK4+UKGhmaOFodmjSaPhoiWjVaNSQaC1OdWJozimBlH2UKGgFfZQoaNJLAmhmjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UaNROaNVo1ymBlH2UKGgFfZQoaGmMBUZhbHNllGggjARoaWdolGhsjAphc3Nlc3NtZW50lGjeiHVoKX2UaCuPlChoIGhpaGxo3pBoLU51YmjhaOMpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaGmMBUZhbHNllGggjARoaWdolGiFTmjqTmhyTmjrTmjsXZRopk5ohk5oiE51aCl9lGgrj5QoaKZo6mhyaCBoC2hpaOxohWjraIZoiJBoLU51Ymh2aHgpgZR9lChoBX2UKGh8XZSMB3ZlcmRpY3SUYWh/jAdwbGFubmVklHVoKX2UaCuPlChof2h8kGgtTnViaPho+imBlH2UKGgFfZQoaAuMBmZhaWxlZJRo/4wJYXZhaWxhYmxllGhuTmoCAQAAjCAwYjkyYjQ0M2ViNjliOWM3MTQzNGZkYzY0ZjJjYThiZZRoZk5oE05qBgEAAE5oJU5qCQEAAE5qCwEAAF2UaGlOaCBOag8BAABOaINOahEBAABOaIZOahQBAABdlGgPTmoYAQAATmhyTmh0TmiIaJ0pgZR9lChoBX2UKGihjA5yZXNlYXJjaF9lbXB0eZRoo4wVaW5zdWZmaWNpZW50X2V2aWRlbmNllGiliWimTminjDFodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjaW5zdWZmaWNpZW50LWV2aWRlbmNllHVoKX2UaCuPlChopmihaKdoo2ilkGgtTnVidWgpfZRoK4+UKGhuaHJqCwEAAGggahgBAABqEQEAAGh0agYBAABoC2oJAQAAaINoZmglaA9oaWiGahQBAABqAgEAAGgTag8BAABo/2iIkGgtTnViaIlOdWgpfZRoK4+UKGhmaOFodmjSaPhoiWjVaNSQaC1OdWJozimBlH2UKGgFfZQoaNJLA2hmjB9QYXJpcyBpcyB0aGUgY2FwaXRhbCBvZiBGcmFuY2UulGjUTmjVaNcpgZR9lChoBX2UKGhpjARUcnVllGggjARoaWdolGhsjAphc3Nlc3NtZW50lGjeiXVoKX2UaCuPlChoIGhpaGxo3pBoLU51YmjhaOMpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaGmMBFRydWWUaCCMBGhpZ2iUaIVOaOpOaHJOaOtOaOxdlGimTmiGTmiITnVoKX2UaCuPlChopmjqaHJoIGgLaGlo7GiFaOtohmiIkGgtTnViaHZoeCmBlH2UKGgFfZQoaHxdlGh/jAxub3Rfc2VsZWN0ZWSUdWgpfZRoK4+UKGh/aHyQaC1OdWJo+E5oiU51aCl9lGgrj5QoaGZo4Wh2aNJo+GiJaNVo1JBoLU51YmWMCWNpdGF0aW9uc5RdlHVoKX2UaCuPlChoxWitaBFoC2gVaMNoXmguaMloVWgPaFFoy2gNaMdoE2gJaoUBAABoS2gHaIiQaC1OdWIu", + "review__get_completed_issues_view_issues.json": "gASVDAsAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjAZpc3N1ZXOUjAZzdGF0dXOUjAljb21wbGV0ZWSUjAdvdXRjb21llIwKaW5jb21wbGV0ZZSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjAhsYW5ndWFnZZSMAmVulIwGcG9saWN5lGgAjBBFc2NhbGF0aW9uUG9saWN5lJOUKYGUfZQoaAV9lCiMCHZlcmRpY3RzlF2UKIwFRmFsc2WUjAxNb3N0bHkgRmFsc2WUjAVNaXhlZJRljApjb25maWRlbmNllF2UjANsb3eUYYwPbWF4X2Fzc2Vzc21lbnRzlEsUjBFtYXhfdmVyaWZpY2F0aW9uc5RLBYwFZGVwdGiUjAhzdGFuZGFyZJSMDW1heF9jaXRhdGlvbnOUSwCMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoJWggaCdoKGgkaCOQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklEsEjAtjbGFpbV9saW1pdJRLFIwTY2xhaW1fbGltaXRfcmVhY2hlZJSJjA9pbnB1dF90cnVuY2F0ZWSUiYwLYXNzZXNzbWVudHOUaACMFlJldmlld0Fzc2Vzc21lbnRDb3VudHOUk5QpgZR9lChoBX2UKIwJY29tcGxldGVklEsDjAZmYWlsZWSUSwF1aCl9lGgrj5QoaD5oP5BoLU51YowNdmVyaWZpY2F0aW9uc5RoAIwYUmV2aWV3VmVyaWZpY2F0aW9uQ291bnRzlJOUKYGUfZQoaAV9lCiMB3BsYW5uZWSUSwJoPksBaD9LAXVoKX2UaCuPlChoPmg/aEiQaC1OdWKMBmlzc3Vlc5RLAowPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJROjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhSaE9oS2g1aE5oUWhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSw1zaCl9lGgrj5QoaFuQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlChoAIwLUmV2aWV3SXNzdWWUk5QpgZR9lChoBX2UKIwLY2xhaW1faW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMDnZlcmlmaWVkX2NsYWltlE6MB3ZlcmRpY3SUjAVGYWxzZZRoIIwEaGlnaJSMBnNvdXJjZZSMDHZlcmlmaWNhdGlvbpSMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwTdmVyaWZpY2F0aW9uX3N0YXR1c5SMCWNvbXBsZXRlZJSMEHZlcmlmaWNhdGlvbl91cmyUjC1odHRwczovL2xlbnouaW8vYXBpL3YxL3ZlcmlmaWNhdGlvbnMvNjhjYTRhYWaUjAN1cmyUjC1odHRwczovL2xlbnouaW8vYy90aGUtZWFydGgtaXMtcm91bmQtNjhjYTRhYWaUjAplc2NhbGF0aW9ulGgAjApFc2NhbGF0aW9ulJOUKYGUfZQoaAV9lCiMDW1hdGNoZWRfcnVsZXOUXZSMB3ZlcmRpY3SUYYwLZGlzcG9zaXRpb26UjAdwbGFubmVklHVoKX2UaCuPlChof2h8kGgtTnVijAtrZXlfZmluZGluZ5SMNEZpbmRpbmcgZm9yIFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAlyYXRpb25hbGWUTowRc3VnZ2VzdGVkX3Jld3JpdGWUjC9GaXhlZDogVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMB2ZhaWx1cmWUTowPc3VnZ2VzdGVkX2VkaXRzlE51aCl9lGgrj5QoaGZobmhyaCBoaWhwaHZohWiJaHRobGhoaGVog2iGaIiQaC1OdWJoYSmBlH2UKGgFfZQoaGVLAmhmjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UaGhOaGmMBUZhbHNllGggjARoaWdolGhsjAphc3Nlc3NtZW50lGhuTmhwjAZmYWlsZWSUaHJOaHROaHZoeCmBlH2UKGgFfZQoaHxdlIwHdmVyZGljdJRhaH+MB3BsYW5uZWSUdWgpfZRoK4+UKGh/aHyQaC1OdWJog05ohU5ohk5oiGgAjAxGYWlsdXJlQmxvY2uUk5QpgZR9lChoBX2UKIwOZmFpbHVyZV9yZWFzb26UjA5yZXNlYXJjaF9lbXB0eZSMDWZhaWx1cmVfY2xhc3OUjBVpbnN1ZmZpY2llbnRfZXZpZGVuY2WUjAlyZXRyeWFibGWUiYwEaGludJROjAhkb2NzX3VybJSMMWh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyNpbnN1ZmZpY2llbnQtZXZpZGVuY2WUdWgpfZRoK4+UKGimaKFop2ijaKWQaC1OdWJoiU51aCl9lGgrj5QoaGZobmhyaCBoaWhwaHZohWiJaHRobGhoaGVog2iGaIiQaC1OdWJljAhmYWlsdXJlc5RdlGgAjA1SZXZpZXdGYWlsdXJllJOUKYGUfZQoaAV9lChoZUsBaGaMIldhdGVyIGJvaWxzIGF0IDEwMCBDIGF0IHNlYSBsZXZlbC6UjAVzdGFnZZSMCmFzc2Vzc21lbnSUaIhonSmBlH2UKGgFfZQoaKGMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGijjBR1cHN0cmVhbV91bmF2YWlsYWJsZZRopYhopoxOQSBtb2RlbCBwcm92aWRlciB3YXMgdW5hdmFpbGFibGUgZm9yIHRoaXMgaXRlbS4gUmV0cnkgaXQ7IG5vdGhpbmcgd2FzIGNoYXJnZWQulGinjDBodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjdXBzdHJlYW0tdW5hdmFpbGFibGWUdWgpfZRoK4+UKGimaKFop2ijaKWQaC1OdWJ1aCl9lGgrj5QoaGZoZWi1aIiQaC1OdWJhaFFdlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMC21vcmVfY2xhaW1zlF2UjBRtb3JlX2NsYWltX2xvY2F0aW9uc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRoiE6MBmNsYWltc5RdlIwJY2l0YXRpb25zlF2UdWgpfZRoK4+UKGjFaK1oEWgLaBVow2heaC5oyWhVaA9oUWgNaMdoE2gJaEtoB2iIkGgtTnViLg==", + "review__get_completed_positions.json": "gASV0QkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwKMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwKMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKX2UaCuPlChoNGg4aDdoTWhCaFJoT2hLaDVoTmhRaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoKX2UaCuPlChoW5BoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UjAdmYWlsdXJllE6MBmNsYWltc5RdlChoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5RdlGgAjAhQb3NpdGlvbpSTlCmBlH2UKGgFfZQojAVzdGFydJRLAIwDZW5klEsojAR0ZXh0lIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpR1aCl9lGgrj5QoaH1ofmh/kGgtTnViYYwGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKIwHdmVyZGljdJSMBFRydWWUaCCMBGhpZ2iUjAZzb3VyY2WUjAphc3Nlc3NtZW50lIwIaXNfaXNzdWWUiXVoKX2UaCuPlChoIGiJaIxojpBoLU51YowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRoiYwEVHJ1ZZRoIIwEaGlnaJSMCXJhdGlvbmFsZZROjAdkaXNzZW50lE6MEHZlcmlmaWNhdGlvbl91cmyUTowKZXJyb3JfY29kZZROjBFpZGVudGlmaWVkX2NsYWltc5RdlIwEaGludJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROaGtOdWgpfZRoK4+UKGigaJtonGggaAtoiWieaJponWihaGuQaC1OdWKMCmVzY2FsYXRpb26UaACMCkVzY2FsYXRpb26Uk5QpgZR9lChoBX2UKIwNbWF0Y2hlZF9ydWxlc5RdlIwLZGlzcG9zaXRpb26UjAxub3Rfc2VsZWN0ZWSUdWgpfZRoK4+UKGisaKqQaC1OdWKMDHZlcmlmaWNhdGlvbpROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoKX2UaCuPlChodGiRaKRoc2iwaLFog2h2kGgtTnViaG8pgZR9lChoBX2UKGhzSwFodIwiV2F0ZXIgYm9pbHMgYXQgMTAwIEMgYXQgc2VhIGxldmVsLpRodl2UaHkpgZR9lChoBX2UKGh9SzdofktZaH+MIldhdGVyIGJvaWxzIGF0IDEwMCBDIGF0IHNlYSBsZXZlbC6UdWgpfZRoK4+UKGh9aH5of5BoLU51YmFog2iFKYGUfZQoaAV9lChoiYwEVHJ1ZZRoIIwEaGlnaJRojIwKYXNzZXNzbWVudJRojol1aCl9lGgrj5QoaCBoiWiMaI6QaC1OdWJokWiTKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGiJjARUcnVllGggjARoaWdolGiaTmibTmicTmidTmieXZRooE5ooU5oa051aCl9lGgrj5QoaKBom2icaCBoC2iJaJ5ommidaKFoa5BoLU51YmikaKYpgZR9lChoBX2UKGiqXZRorIwMbm90X3NlbGVjdGVklHVoKX2UaCuPlChorGiqkGgtTnViaLBOaLFOdWgpfZRoK4+UKGh0aJFopGhzaLBosWiDaHaQaC1OdWJljAljaXRhdGlvbnOUXZR1aCl9lGgrj5QoaGVoYGgRaAtoFWhjaF5oLmhpaFVoD2hRaGxoDWhnaBNoCWjZaEtoB2hrkGgtTnViLg==", + "review__get_completed_recovered_claim.json": "gASVuQcAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwGMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKX2UaCuPlChoNGg4aDdoTWhCaFJoT2hLaDVoTmhRaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAXNoKX2UaCuPlChoW5BoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UjAdmYWlsdXJllE6MBmNsYWltc5RdlGgAjAtSZXZpZXdDbGFpbZSTlCmBlH2UKGgFfZQojAVpbmRleJRLAIwFY2xhaW2UjCxPcmJpdCBNb3RvcnMgc3RvY2sgaW5jcmVhc2VkIGJ5IDQwJSBpbiAyMDIyLpSMCXBvc2l0aW9uc5RdlIwGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKIwHdmVyZGljdJSMBFRydWWUaCCMBGhpZ2iUjAZzb3VyY2WUjAphc3Nlc3NtZW50lIwIaXNfaXNzdWWUiXVoKX2UaCuPlChoIGh+aIFog5BoLU51YowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRofowEVHJ1ZZRoIIwEaGlnaJSMCXJhdGlvbmFsZZROjAdkaXNzZW50lE6MEHZlcmlmaWNhdGlvbl91cmyUTowKZXJyb3JfY29kZZROjBFpZGVudGlmaWVkX2NsYWltc5RdlIwEaGludJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROaGtOdWgpfZRoK4+UKGiVaJBokWggaAtofmiTaI9okmiWaGuQaC1OdWKMCmVzY2FsYXRpb26UaACMCkVzY2FsYXRpb26Uk5QpgZR9lChoBX2UKIwNbWF0Y2hlZF9ydWxlc5RdlIwLZGlzcG9zaXRpb26UjAxub3Rfc2VsZWN0ZWSUdWgpfZRoK4+UKGihaJ+QaC1OdWKMDHZlcmlmaWNhdGlvbpROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoKX2UaCuPlChodGiGaJloc2ilaKZoeGh2kGgtTnViYYwJY2l0YXRpb25zlF2UdWgpfZRoK4+UKGhlaGBoEWgLaBVoY2heaC5oaWhVaA9oUWhsaA1oZ2gTaAloqWhLaAdoa5BoLU51Yi4=", + "review__get_completed_with_untraced_claim.json": "gASV0QkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwKMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwKMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKX2UaCuPlChoNGg4aDdoTWhCaFJoT2hLaDVoTmhRaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoKX2UaCuPlChoW5BoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UjAdmYWlsdXJllE6MBmNsYWltc5RdlChoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5RdlGgAjAhQb3NpdGlvbpSTlCmBlH2UKGgFfZQojAVzdGFydJRLAIwDZW5klEsojAR0ZXh0lIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpR1aCl9lGgrj5QoaH1ofmh/kGgtTnViYYwGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKIwHdmVyZGljdJSMBFRydWWUaCCMBGhpZ2iUjAZzb3VyY2WUjAphc3Nlc3NtZW50lIwIaXNfaXNzdWWUiXVoKX2UaCuPlChoIGiJaIxojpBoLU51YowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRoiYwEVHJ1ZZRoIIwEaGlnaJSMCXJhdGlvbmFsZZROjAdkaXNzZW50lE6MEHZlcmlmaWNhdGlvbl91cmyUTowKZXJyb3JfY29kZZROjBFpZGVudGlmaWVkX2NsYWltc5RdlIwEaGludJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROaGtOdWgpfZRoK4+UKGigaJtonGggaAtoiWieaJponWihaGuQaC1OdWKMCmVzY2FsYXRpb26UaACMCkVzY2FsYXRpb26Uk5QpgZR9lChoBX2UKIwNbWF0Y2hlZF9ydWxlc5RdlIwLZGlzcG9zaXRpb26UjAxub3Rfc2VsZWN0ZWSUdWgpfZRoK4+UKGisaKqQaC1OdWKMDHZlcmlmaWNhdGlvbpROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoKX2UaCuPlChodGiRaKRoc2iwaLFog2h2kGgtTnViaG8pgZR9lChoBX2UKGhzSwFodIwiV2F0ZXIgYm9pbHMgYXQgMTAwIEMgYXQgc2VhIGxldmVsLpRodl2UaHkpgZR9lChoBX2UKGh9SzJofktUaH+MIldhdGVyIGJvaWxzIGF0IDEwMCBDIGF0IHNlYSBsZXZlbC6UdWgpfZRoK4+UKGh9aH5of5BoLU51YmFog2iFKYGUfZQoaAV9lChoiYwEVHJ1ZZRoIIwEaGlnaJRojIwKYXNzZXNzbWVudJRojol1aCl9lGgrj5QoaCBoiWiMaI6QaC1OdWJokWiTKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGiJjARUcnVllGggjARoaWdolGiaTmibTmicTmidTmieXZRooE5ooU5oa051aCl9lGgrj5QoaKBom2icaCBoC2iJaJ5ommidaKFoa5BoLU51YmikaKYpgZR9lChoBX2UKGiqXZRorIwMbm90X3NlbGVjdGVklHVoKX2UaCuPlChorGiqkGgtTnViaLBOaLFOdWgpfZRoK4+UKGh0aJFopGhzaLBosWiDaHaQaC1OdWJljAljaXRhdGlvbnOUXZR1aCl9lGgrj5QoaGVoYGgRaAtoFWhjaF5oLmhpaFVoD2hRaGxoDWhnaBNoCWjZaEtoB2hrkGgtTnViLg==", + "review__get_during_quick_check.json": "gASVaQYAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJYXNzZXNzaW5nlIwHb3V0Y29tZZROjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGWgjaB5oJWgmaCJoIZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwCMBmZhaWxlZJRLAHVoJ32UaCmPlChoPGg9kGgrTnVijA12ZXJpZmljYXRpb25zlE6MBmlzc3Vlc5RLAIwPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJROjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCd9lGgpj5QoaDJoNmg1aENoQGhIaEVoQWgzaERoR2hGaEJoNJBoK051YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwFzaCd9lGgpj5QoaFGQaCtOdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5RLCmhBXZSMCGZhaWx1cmVzlF2UaEddlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMC21vcmVfY2xhaW1zlF2UjBRtb3JlX2NsYWltX2xvY2F0aW9uc5RdlIwObW9yZV9jaXRhdGlvbnOUXZSMB2ZhaWx1cmWUTowGY2xhaW1zlF2UaACMC1Jldmlld0NsYWltlJOUKYGUfZQoaAV9lCiMBWluZGV4lEsAjAVjbGFpbZSMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAlwb3NpdGlvbnOUTowGcmVzdWx0lE6MCmFzc2Vzc21lbnSUaACMEFJldmlld0Fzc2Vzc21lbnSUk5QpgZR9lChoBX2UKGgLjAdydW5uaW5nlIwHdmVyZGljdJROaB5OjAlyYXRpb25hbGWUTowHZGlzc2VudJROjBB2ZXJpZmljYXRpb25fdXJslE6MCmVycm9yX2NvZGWUTowRaWRlbnRpZmllZF9jbGFpbXOUXZSMBGhpbnSUTowRc3VnZ2VzdGVkX3Jld3JpdGWUTmhhTnVoJ32UaCmPlChofGh3aHhoHmgLaHVoemh2aHlofWhhkGgrTnVijAplc2NhbGF0aW9ulE6MDHZlcmlmaWNhdGlvbpROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoJ32UaCmPlChoamhuaIBoaWiBaIJobWhskGgrTnViYYwJY2l0YXRpb25zlF2UdWgnfZRoKY+UKGhbaFZoEGgLaBNoWWhUaCxoX2hLaA5oR2hiaA1oXWgRaAlohWhBaAdoYZBoK051Yi4=", + "review__get_failed_every_assessment_failed.json": "gASVfw0AAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwGZmFpbGVklIwHb3V0Y29tZZSMCmluY29tcGxldGWUjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lIwbMjAyNi0xMC0wMVQxMDowNzowMC4xMjM0NTZalIwIbGFuZ3VhZ2WUjAJlbpSMBnBvbGljeZRoAIwQRXNjYWxhdGlvblBvbGljeZSTlCmBlH2UKGgFfZQojAh2ZXJkaWN0c5RdlCiMBUZhbHNllIwMTW9zdGx5IEZhbHNllIwFTWl4ZWSUZYwKY29uZmlkZW5jZZRdlIwDbG93lGGMD21heF9hc3Nlc3NtZW50c5RLFIwRbWF4X3ZlcmlmaWNhdGlvbnOUSwWMBWRlcHRolIwIc3RhbmRhcmSUjA1tYXhfY2l0YXRpb25zlEsAjA1zdWdnZXN0X2VkaXRzlIl1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgbaCVoIGgnaChoJGgjkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjA1SZXZpZXdTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NsYWltc19zZWxlY3RlZJRLAowLY2xhaW1fbGltaXSUSxSME2NsYWltX2xpbWl0X3JlYWNoZWSUiYwPaW5wdXRfdHJ1bmNhdGVklImMC2Fzc2Vzc21lbnRzlGgAjBZSZXZpZXdBc3Nlc3NtZW50Q291bnRzlJOUKYGUfZQoaAV9lCiMCWNvbXBsZXRlZJRLAIwGZmFpbGVklEsCdWgpfZRoK4+UKGg+aD+QaC1OdWKMDXZlcmlmaWNhdGlvbnOUaACMGFJldmlld1ZlcmlmaWNhdGlvbkNvdW50c5STlCmBlH2UKGgFfZQojAdwbGFubmVklEsAaD5LAGg/SwB1aCl9lGgrj5QoaD5oP2hIkGgtTnVijAZpc3N1ZXOUSwCMD2NpdGF0aW9uc19mb3VuZJROjBJjaXRhdGlvbnNfc2VsZWN0ZWSUTowOY2l0YXRpb25fbGltaXSUTowWY2l0YXRpb25fbGltaXRfcmVhY2hlZJROjA9jaXRhdGlvbl9jaGVja3OUTowPY2l0YXRpb25faXNzdWVzlEsAjBFjaXRhdGlvbnNfc2tpcHBlZJROdWgpfZRoK4+UKGg0aDhoN2hNaEJoUmhPaEtoNWhOaFFoUGhMaDaQaC1OdWKMB2NyZWRpdHOUaACMDVJldmlld0NyZWRpdHOUk5QpgZR9lChoBX2UjAdjaGFyZ2VklEsAc2gpfZRoK4+UKGhbkGgtTnVijBJwb2xsX2FmdGVyX3NlY29uZHOUTmhLXZSMCGZhaWx1cmVzlF2UKGgAjA1SZXZpZXdGYWlsdXJllJOUKYGUfZQoaAV9lCiMC2NsYWltX2luZGV4lEsAjAVjbGFpbZSMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UjAVzdGFnZZSMCmFzc2Vzc21lbnSUjAdmYWlsdXJllGgAjAxGYWlsdXJlQmxvY2uUk5QpgZR9lChoBX2UKIwOZmFpbHVyZV9yZWFzb26UjBR1cHN0cmVhbV91bmF2YWlsYWJsZZSMDWZhaWx1cmVfY2xhc3OUjBR1cHN0cmVhbV91bmF2YWlsYWJsZZSMCXJldHJ5YWJsZZSIjARoaW50lIxOQSBtb2RlbCBwcm92aWRlciB3YXMgdW5hdmFpbGFibGUgZm9yIHRoaXMgaXRlbS4gUmV0cnkgaXQ7IG5vdGhpbmcgd2FzIGNoYXJnZWQulIwIZG9jc191cmyUjDBodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjdXBzdHJlYW0tdW5hdmFpbGFibGWUdWgpfZRoK4+UKGh3aHJoeWh0aHaQaC1OdWJ1aCl9lGgrj5QoaGhoZ2hqaGyQaC1OdWJoYymBlH2UKGgFfZQoaGdLAWhojCJXYXRlciBib2lscyBhdCAxMDAgQyBhdCBzZWEgbGV2ZWwulGhqjAphc3Nlc3NtZW50lGhsaG4pgZR9lChoBX2UKGhyjBR1cHN0cmVhbV91bmF2YWlsYWJsZZRodIwUdXBzdHJlYW1fdW5hdmFpbGFibGWUaHaIaHeMTkEgbW9kZWwgcHJvdmlkZXIgd2FzIHVuYXZhaWxhYmxlIGZvciB0aGlzIGl0ZW0uIFJldHJ5IGl0OyBub3RoaW5nIHdhcyBjaGFyZ2VkLpRoeYwwaHR0cHM6Ly9sZW56LmlvL2RvY3MvZXJyb3JzI3Vwc3RyZWFtLXVuYXZhaWxhYmxllHVoKX2UaCuPlChod2hyaHlodGh2kGgtTnVidWgpfZRoK4+UKGhoaGdoamhskGgtTnViZWhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UaGxobimBlH2UKGgFfZQoaHKMEWFzc2Vzc21lbnRfZmFpbGVklGh0jBR1cHN0cmVhbV91bmF2YWlsYWJsZZRodohod4xdTm8gY2xhaW0gY291bGQgYmUgYXNzZXNzZWQuIFJldHJ5IHRoZSByZXZpZXcgd2l0aCBhIG5ldyBJZGVtcG90ZW5jeS1LZXk7IG5vdGhpbmcgd2FzIGNoYXJnZWQulGh5jDBodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjdXBzdHJlYW0tdW5hdmFpbGFibGWUdWgpfZRoK4+UKGh3aHJoeWh0aHaQaC1OdWKMBmNsYWltc5RdlChoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwBoaIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUTowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMBmZhaWxlZJSMB3ZlcmRpY3SUTmggTowJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowQdmVyaWZpY2F0aW9uX3VybJROjAplcnJvcl9jb2RllIwUdXBzdHJlYW1fdW5hdmFpbGFibGWUjBFpZGVudGlmaWVkX2NsYWltc5RdlGh3TowRc3VnZ2VzdGVkX3Jld3JpdGWUTmhsaG4pgZR9lChoBX2UKGhyjBR1cHN0cmVhbV91bmF2YWlsYWJsZZRodIwUdXBzdHJlYW1fdW5hdmFpbGFibGWUaHaIaHeMTkEgbW9kZWwgcHJvdmlkZXIgd2FzIHVuYXZhaWxhYmxlIGZvciB0aGlzIGl0ZW0uIFJldHJ5IGl0OyBub3RoaW5nIHdhcyBjaGFyZ2VkLpRoeYwwaHR0cHM6Ly9sZW56LmlvL2RvY3MvZXJyb3JzI3Vwc3RyZWFtLXVuYXZhaWxhYmxllHVoKX2UaCuPlChod2hyaHlodGh2kGgtTnVidWgpfZRoK4+UKGh3aLVotmggaAtos2i5aLRot2i7aGyQaC1OdWKMCmVzY2FsYXRpb26UTowMdmVyaWZpY2F0aW9ulE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgpfZRoK4+UKGhoaKxox2ioaMhoyWiraKqQaC1OdWJopCmBlH2UKGgFfZQoaKhLAWhojCJXYXRlciBib2lscyBhdCAxMDAgQyBhdCBzZWEgbGV2ZWwulGiqTmirTmisaK4pgZR9lChoBX2UKGgLjAZmYWlsZWSUaLNOaCBOaLROaLVOaLZOaLeMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGi5XZRod05ou05obGhuKYGUfZQoaAV9lChocowUdXBzdHJlYW1fdW5hdmFpbGFibGWUaHSMFHVwc3RyZWFtX3VuYXZhaWxhYmxllGh2iGh3jE5BIG1vZGVsIHByb3ZpZGVyIHdhcyB1bmF2YWlsYWJsZSBmb3IgdGhpcyBpdGVtLiBSZXRyeSBpdDsgbm90aGluZyB3YXMgY2hhcmdlZC6UaHmMMGh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyN1cHN0cmVhbS11bmF2YWlsYWJsZZR1aCl9lGgrj5QoaHdocmh5aHRodpBoLU51YnVoKX2UaCuPlChod2i1aLZoIGgLaLNouWi0aLdou2hskGgtTnViaMdOaMhOaMlOdWgpfZRoK4+UKGhoaKxox2ioaMhoyWiraKqQaC1OdWJljAljaXRhdGlvbnOUXZR1aCl9lGgrj5QoaJJoYGgRaAtoFWiQaF5oLmiWaFVoD2hRaKFoDWiUaBNoCWjjaEtoB2hskGgtTnViLg==", + "review__get_failed_no_claim.json": "gASV3gUAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwGZmFpbGVklIwHb3V0Y29tZZSMCXVuY2hlY2tlZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjAhsYW5ndWFnZZSMAmVulIwGcG9saWN5lGgAjBBFc2NhbGF0aW9uUG9saWN5lJOUKYGUfZQoaAV9lCiMCHZlcmRpY3RzlF2UKIwFRmFsc2WUjAxNb3N0bHkgRmFsc2WUjAVNaXhlZJRljApjb25maWRlbmNllF2UjANsb3eUYYwPbWF4X2Fzc2Vzc21lbnRzlEsUjBFtYXhfdmVyaWZpY2F0aW9uc5RLBYwFZGVwdGiUjAhzdGFuZGFyZJSMDW1heF9jaXRhdGlvbnOUSwCMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoJWggaCdoKGgkaCOQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklE6MC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklE6MD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5ROjA12ZXJpZmljYXRpb25zlE6MBmlzc3Vlc5RLAIwPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJROjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aDxoOWhBaD5oOmg1aD1oQGg/aDtoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwBzaCl9lGgrj5QoaEqQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaDpdlIwIZmFpbHVyZXOUXZRoQF2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUTowUbW9yZV9jbGFpbV9sb2NhdGlvbnOUTowObW9yZV9jaXRhdGlvbnOUTowHZmFpbHVyZZRoAIwMRmFpbHVyZUJsb2NrlJOUKYGUfZQoaAV9lCiMDmZhaWx1cmVfcmVhc29ulIwIbm9fY2xhaW2UjA1mYWlsdXJlX2NsYXNzlIwNaW52YWxpZF9pbnB1dJSMCXJldHJ5YWJsZZSJjARoaW50lIyKVGhlIHRleHQgaXMgYSBncmVldGluZywgbm90IGEgc3RhdGVtZW50IGFib3V0IHRoZSB3b3JsZC4gU2VuZCBvbmUgZmFjdHVhbCBjbGFpbSwgb3IgcnVuIHRoZSB0ZXh0IHRocm91Z2ggL2V4dHJhY3QgdG8gZW51bWVyYXRlIGl0cyBjbGFpbXMulIwIZG9jc191cmyUjClodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjaW52YWxpZC1pbnB1dJR1aCl9lGgrj5QoaGJoXWhkaF9oYZBoLU51YowGY2xhaW1zlF2UjAljaXRhdGlvbnOUXZR1aCl9lGgrj5QoaFRoT2gRaAtoFWhSaE1oLmhWaERoD2hAaGhoDWhVaBNoCWhqaDpoB2hXkGgtTnViLg==", + "review__get_failed_no_claim_untraced.json": "gASV5gUAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwGZmFpbGVklIwHb3V0Y29tZZSMCXVuY2hlY2tlZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjAhsYW5ndWFnZZSMAmVulIwGcG9saWN5lGgAjBBFc2NhbGF0aW9uUG9saWN5lJOUKYGUfZQoaAV9lCiMCHZlcmRpY3RzlF2UKIwFRmFsc2WUjAxNb3N0bHkgRmFsc2WUjAVNaXhlZJRljApjb25maWRlbmNllF2UjANsb3eUYYwPbWF4X2Fzc2Vzc21lbnRzlEsUjBFtYXhfdmVyaWZpY2F0aW9uc5RLBYwFZGVwdGiUjAhzdGFuZGFyZJSMDW1heF9jaXRhdGlvbnOUSwCMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoJWggaCdoKGgkaCOQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklE6MC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklE6MD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5ROjA12ZXJpZmljYXRpb25zlE6MBmlzc3Vlc5RLAIwPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJROjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aDxoOWhBaD5oOmg1aD1oQGg/aDtoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwBzaCl9lGgrj5QoaEqQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaDpdlIwIZmFpbHVyZXOUXZRoQF2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUTowUbW9yZV9jbGFpbV9sb2NhdGlvbnOUTowObW9yZV9jaXRhdGlvbnOUTowHZmFpbHVyZZRoAIwMRmFpbHVyZUJsb2NrlJOUKYGUfZQoaAV9lCiMDmZhaWx1cmVfcmVhc29ulIwIbm9fY2xhaW2UjA1mYWlsdXJlX2NsYXNzlIwNaW52YWxpZF9pbnB1dJSMCXJldHJ5YWJsZZSJjARoaW50lIySTm9uZSBvZiB0aGUgY2xhaW1zIGZvdW5kIGluIHRoZSB0ZXh0IGNvdWxkIGJlIHRyYWNlZCBiYWNrIHRvIGl0LiBTZW5kIG9uZSBmYWN0dWFsIGNsYWltLCBvciBydW4gdGhlIHRleHQgdGhyb3VnaCAvZXh0cmFjdCB0byBlbnVtZXJhdGUgaXRzIGNsYWltcy6UjAhkb2NzX3VybJSMKWh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyNpbnZhbGlkLWlucHV0lHVoKX2UaCuPlChoYmhdaGRoX2hhkGgtTnVijAZjbGFpbXOUXZSMCWNpdGF0aW9uc5RdlHVoKX2UaCuPlChoVGhPaBFoC2gVaFJoTWguaFZoRGgPaEBoaGgNaFVoE2gJaGpoOmgHaFeQaC1OdWIu", + "review__get_more_claims.json": "gASVnQoAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSwKMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwKMC2NsYWltX2xpbWl0lEsCjBNjbGFpbV9saW1pdF9yZWFjaGVklIiMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwKMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKX2UaCuPlChoNGg4aDdoTWhCaFJoT2hLaDVoTmhRaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoKX2UaCuPlChoW5BoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIweVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulGGMFG1vcmVfY2xhaW1fbG9jYXRpb25zlF2UaACMDUNsYWltTG9jYXRpb26Uk5QpgZR9lChoBX2UKIwFY2xhaW2UjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjAlwb3NpdGlvbnOUXZRoAIwIUG9zaXRpb26Uk5QpgZR9lChoBX2UKIwFc3RhcnSUS1uMA2VuZJRLeYwEdGV4dJSMHlRoZSBFaWZmZWwgVG93ZXIgaXMgaW4gQmVybGluLpR1aCl9lGgrj5QoaHhoeWh6kGgtTnViYXVoKX2UaCuPlChob2hxkGgtTnViYYwObW9yZV9jaXRhdGlvbnOUXZSMB2ZhaWx1cmWUTowGY2xhaW1zlF2UKGgAjAtSZXZpZXdDbGFpbZSTlCmBlH2UKGgFfZQojAVpbmRleJRLAGhvjChUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulGhxXZRodCmBlH2UKGgFfZQoaHhLAGh5SyhoeowoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpR1aCl9lGgrj5QoaHhoeWh6kGgtTnViYYwGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKIwHdmVyZGljdJSMBFRydWWUaCCMBGhpZ2iUjAZzb3VyY2WUjAphc3Nlc3NtZW50lIwIaXNfaXNzdWWUiXVoKX2UaCuPlChoIGiZaJxonpBoLU51YowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRomYwEVHJ1ZZRoIIwEaGlnaJSMCXJhdGlvbmFsZZROjAdkaXNzZW50lE6MEHZlcmlmaWNhdGlvbl91cmyUTowKZXJyb3JfY29kZZROjBFpZGVudGlmaWVkX2NsYWltc5RdlIwEaGludJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROaIJOdWgpfZRoK4+UKGiwaKtorGggaAtomWiuaKporWixaIKQaC1OdWKMCmVzY2FsYXRpb26UaACMCkVzY2FsYXRpb26Uk5QpgZR9lChoBX2UKIwNbWF0Y2hlZF9ydWxlc5RdlIwLZGlzcG9zaXRpb26UjAxub3Rfc2VsZWN0ZWSUdWgpfZRoK4+UKGi8aLqQaC1OdWKMDHZlcmlmaWNhdGlvbpROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoKX2UaCuPlChob2ihaLRoimjAaMFok2hxkGgtTnViaIYpgZR9lChoBX2UKGiKSwFob4wiV2F0ZXIgYm9pbHMgYXQgMTAwIEMgYXQgc2VhIGxldmVsLpRocV2UaHQpgZR9lChoBX2UKGh4SzJoeUtUaHqMIldhdGVyIGJvaWxzIGF0IDEwMCBDIGF0IHNlYSBsZXZlbC6UdWgpfZRoK4+UKGh4aHloepBoLU51YmFok2iVKYGUfZQoaAV9lChomYwEVHJ1ZZRoIIwEaGlnaJRonIwKYXNzZXNzbWVudJRonol1aCl9lGgrj5QoaCBomWicaJ6QaC1OdWJooWijKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGiZjARUcnVllGggjARoaWdolGiqTmirTmisTmitTmiuXZRosE5osU5ogk51aCl9lGgrj5QoaLBoq2isaCBoC2iZaK5oqmitaLFogpBoLU51Ymi0aLYpgZR9lChoBX2UKGi6XZRovIwMbm90X3NlbGVjdGVklHVoKX2UaCuPlChovGi6kGgtTnViaMBOaMFOdWgpfZRoK4+UKGhvaKFotGiKaMBowWiTaHGQaC1OdWJljAljaXRhdGlvbnOUXZR1aCl9lGgrj5QoaGVoYGgRaAtoFWhjaF5oLmiAaFVoD2hRaINoDWhoaBNoCWjpaEtoB2iCkGgtTnViLg==", + "review__get_nested_verification_modified_at_crosses_midnight_by_minutes.json": "gASVfAwAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMDGlzc3Vlc19mb3VuZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjAhsYW5ndWFnZZSMAmVulIwGcG9saWN5lGgAjBBFc2NhbGF0aW9uUG9saWN5lJOUKYGUfZQoaAV9lCiMCHZlcmRpY3RzlF2UKIwFRmFsc2WUjAxNb3N0bHkgRmFsc2WUjAVNaXhlZJRljApjb25maWRlbmNllF2UjANsb3eUYYwPbWF4X2Fzc2Vzc21lbnRzlEsUjBFtYXhfdmVyaWZpY2F0aW9uc5RLBYwFZGVwdGiUjAhzdGFuZGFyZJSMDW1heF9jaXRhdGlvbnOUSwCMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoJWggaCdoKGgkaCOQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklEsBjAtjbGFpbV9saW1pdJRLFIwTY2xhaW1fbGltaXRfcmVhY2hlZJSJjA9pbnB1dF90cnVuY2F0ZWSUiYwLYXNzZXNzbWVudHOUaACMFlJldmlld0Fzc2Vzc21lbnRDb3VudHOUk5QpgZR9lChoBX2UKIwJY29tcGxldGVklEsBjAZmYWlsZWSUSwB1aCl9lGgrj5QoaD5oP5BoLU51YowNdmVyaWZpY2F0aW9uc5RoAIwYUmV2aWV3VmVyaWZpY2F0aW9uQ291bnRzlJOUKYGUfZQoaAV9lCiMB3BsYW5uZWSUSwFoPksBaD9LAHVoKX2UaCuPlChoPmg/aEiQaC1OdWKMBmlzc3Vlc5RLAYwPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJROjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhSaE9oS2g1aE5oUWhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwtzaCl9lGgrj5QoaFuQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlGgAjAtSZXZpZXdJc3N1ZZSTlCmBlH2UKGgFfZQojAtjbGFpbV9pbmRleJRLAIwFY2xhaW2UjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjA52ZXJpZmllZF9jbGFpbZROjAd2ZXJkaWN0lIwFRmFsc2WUaCCMBGhpZ2iUjAZzb3VyY2WUjAx2ZXJpZmljYXRpb26UjA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSME3ZlcmlmaWNhdGlvbl9zdGF0dXOUjAljb21wbGV0ZWSUjBB2ZXJpZmljYXRpb25fdXJslIwtaHR0cHM6Ly9sZW56LmlvL2FwaS92MS92ZXJpZmljYXRpb25zLzY4Y2E0YWFmlIwDdXJslIwtaHR0cHM6Ly9sZW56LmlvL2MvdGhlLWVhcnRoLWlzLXJvdW5kLTY4Y2E0YWFmlIwKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAd2ZXJkaWN0lGGMC2Rpc3Bvc2l0aW9ulIwHcGxhbm5lZJR1aCl9lGgrj5QoaH9ofJBoLU51YowLa2V5X2ZpbmRpbmeUjCpGaW5kaW5nIGZvciBUaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjAlyYXRpb25hbGWUTowRc3VnZ2VzdGVkX3Jld3JpdGWUjCVGaXhlZDogVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulIwHZmFpbHVyZZROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoKX2UaCuPlChoZmhuaHJoIGhpaHBodmiFaIlodGhsaGhoZWiDaIZoiJBoLU51YmGMCGZhaWx1cmVzlF2UaFFdlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMC21vcmVfY2xhaW1zlF2UjBRtb3JlX2NsYWltX2xvY2F0aW9uc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRoiE6MBmNsYWltc5RdlGgAjAtSZXZpZXdDbGFpbZSTlCmBlH2UKGgFfZQojAVpbmRleJRLAGhmjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjAlwb3NpdGlvbnOUTowGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKGhpjAVGYWxzZZRoIIwEaGlnaJRobIwMdmVyaWZpY2F0aW9ulIwIaXNfaXNzdWWUiHVoKX2UaCuPlChoIGhpaGxoqpBoLU51YowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRoaYwFRmFsc2WUaCCMBGhpZ2iUaIVOjAdkaXNzZW50lE5ock6MCmVycm9yX2NvZGWUTowRaWRlbnRpZmllZF9jbGFpbXOUXZSMBGhpbnSUTmiGTmiITnVoKX2UaCuPlChoumi2aHJoIGgLaGlouGiFaLdohmiIkGgtTnViaHZoeCmBlH2UKGgFfZQoaHxdlIwHdmVyZGljdJRhaH+MB3BsYW5uZWSUdWgpfZRoK4+UKGh/aHyQaC1OdWKMDHZlcmlmaWNhdGlvbpRoAIwSUmV2aWV3VmVyaWZpY2F0aW9ulJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklIwOY29udGVudF9zdGF0dXOUjAlhdmFpbGFibGWUaG6MCDY4Y2E0YWFmlIwHdGFza19pZJSMIDdjZmYxOGRhMmQ5NzlkNjM3MGU1NGExNjBiZTEyMWFklGhmjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UaBOMAmVulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUaCWMCHN0YW5kYXJklIwGZG9tYWlulIwAlIwIZW50aXRpZXOUXZRoaYwFRmFsc2WUaCCMBGhpZ2iUjApsZW56X3Njb3JllEsCaIOMKkZpbmRpbmcgZm9yIFRoZSBFaWZmZWwgVG93ZXIgaXMgaW4gQmVybGluLpSMEWV4ZWN1dGl2ZV9zdW1tYXJ5lIwqU3VtbWFyeSBmb3IgVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulGiGjCVGaXhlZDogVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulIwId2FybmluZ3OUXZSMAncxlGFoD4wgMjAyNi0xMC0wMVQyMzo1NTowMC4xMjM0NTYrMDA6MDCUjAttb2RpZmllZF9hdJSMIDIwMjYtMTAtMDJUMDA6MDM6MDAuMTIzNDU2KzAwOjAwlGhyjC1odHRwczovL2xlbnouaW8vYXBpL3YxL3ZlcmlmaWNhdGlvbnMvNjhjYTRhYWaUaHSMLWh0dHBzOi8vbGVuei5pby9jL3RoZS1lYXJ0aC1pcy1yb3VuZC02OGNhNGFhZpRoiE51aCl9lGgrj5QoaG5ocmjYaCBo5WjeaHRo02gLaNZog2hmaCVoD2hpaIZo4WjPaBNo3GjMaIiQaC1OdWJoiU51aCl9lGgrj5QoaGZorWh2aJ5oxWiJaKFooJBoLU51YmGMCWNpdGF0aW9uc5RdlHVoKX2UaCuPlChokWiMaBFoC2gVaI9oXmguaJVoVWgPaFFol2gNaJNoE2gJaO1oS2gHaIiQaC1OdWIu", + "review__get_nested_verification_modified_at_same_day_hours_apart.json": "gASVWgwAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMDGlzc3Vlc19mb3VuZJSMCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUjBsyMDI2LTEwLTAxVDEwOjA3OjAwLjEyMzQ1NlqUjAhsYW5ndWFnZZSMAmVulIwGcG9saWN5lGgAjBBFc2NhbGF0aW9uUG9saWN5lJOUKYGUfZQoaAV9lCiMCHZlcmRpY3RzlF2UKIwFRmFsc2WUjAxNb3N0bHkgRmFsc2WUjAVNaXhlZJRljApjb25maWRlbmNllF2UjANsb3eUYYwPbWF4X2Fzc2Vzc21lbnRzlEsUjBFtYXhfdmVyaWZpY2F0aW9uc5RLBYwFZGVwdGiUjAhzdGFuZGFyZJSMDW1heF9jaXRhdGlvbnOUSwCMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoJWggaCdoKGgkaCOQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklEsBjAtjbGFpbV9saW1pdJRLFIwTY2xhaW1fbGltaXRfcmVhY2hlZJSJjA9pbnB1dF90cnVuY2F0ZWSUiYwLYXNzZXNzbWVudHOUaACMFlJldmlld0Fzc2Vzc21lbnRDb3VudHOUk5QpgZR9lChoBX2UKIwJY29tcGxldGVklEsBjAZmYWlsZWSUSwB1aCl9lGgrj5QoaD5oP5BoLU51YowNdmVyaWZpY2F0aW9uc5RoAIwYUmV2aWV3VmVyaWZpY2F0aW9uQ291bnRzlJOUKYGUfZQoaAV9lCiMB3BsYW5uZWSUSwFoPksBaD9LAHVoKX2UaCuPlChoPmg/aEiQaC1OdWKMBmlzc3Vlc5RLAYwPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJROjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCl9lGgrj5QoaDRoOGg3aE1oQmhSaE9oS2g1aE5oUWhQaExoNpBoLU51YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwtzaCl9lGgrj5QoaFuQaC1OdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEtdlGgAjAtSZXZpZXdJc3N1ZZSTlCmBlH2UKGgFfZQojAtjbGFpbV9pbmRleJRLAIwFY2xhaW2UjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjA52ZXJpZmllZF9jbGFpbZROjAd2ZXJkaWN0lIwFRmFsc2WUaCCMBGhpZ2iUjAZzb3VyY2WUjAx2ZXJpZmljYXRpb26UjA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSME3ZlcmlmaWNhdGlvbl9zdGF0dXOUjAljb21wbGV0ZWSUjBB2ZXJpZmljYXRpb25fdXJslIwtaHR0cHM6Ly9sZW56LmlvL2FwaS92MS92ZXJpZmljYXRpb25zLzY4Y2E0YWFmlIwDdXJslIwtaHR0cHM6Ly9sZW56LmlvL2MvdGhlLWVhcnRoLWlzLXJvdW5kLTY4Y2E0YWFmlIwKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAd2ZXJkaWN0lGGMC2Rpc3Bvc2l0aW9ulIwHcGxhbm5lZJR1aCl9lGgrj5QoaH9ofJBoLU51YowLa2V5X2ZpbmRpbmeUjCpGaW5kaW5nIGZvciBUaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjAlyYXRpb25hbGWUTowRc3VnZ2VzdGVkX3Jld3JpdGWUjCVGaXhlZDogVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulIwHZmFpbHVyZZROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoKX2UaCuPlChoZmhuaHJoIGhpaHBodmiFaIlodGhsaGhoZWiDaIZoiJBoLU51YmGMCGZhaWx1cmVzlF2UaFFdlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMC21vcmVfY2xhaW1zlF2UjBRtb3JlX2NsYWltX2xvY2F0aW9uc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRoiE6MBmNsYWltc5RdlGgAjAtSZXZpZXdDbGFpbZSTlCmBlH2UKGgFfZQojAVpbmRleJRLAGhmjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjAlwb3NpdGlvbnOUTowGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKGhpjAVGYWxzZZRoIIwEaGlnaJRobIwMdmVyaWZpY2F0aW9ulIwIaXNfaXNzdWWUiHVoKX2UaCuPlChoIGhpaGxoqpBoLU51YowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRoaYwFRmFsc2WUaCCMBGhpZ2iUaIVOjAdkaXNzZW50lE5ock6MCmVycm9yX2NvZGWUTowRaWRlbnRpZmllZF9jbGFpbXOUXZSMBGhpbnSUTmiGTmiITnVoKX2UaCuPlChoumi2aHJoIGgLaGlouGiFaLdohmiIkGgtTnViaHZoeCmBlH2UKGgFfZQoaHxdlIwHdmVyZGljdJRhaH+MB3BsYW5uZWSUdWgpfZRoK4+UKGh/aHyQaC1OdWKMDHZlcmlmaWNhdGlvbpRoAIwSUmV2aWV3VmVyaWZpY2F0aW9ulJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklIwOY29udGVudF9zdGF0dXOUjAlhdmFpbGFibGWUaG6MCDY4Y2E0YWFmlIwHdGFza19pZJSMIDdjZmYxOGRhMmQ5NzlkNjM3MGU1NGExNjBiZTEyMWFklGhmjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UaBOMAmVulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUaCWMCHN0YW5kYXJklIwGZG9tYWlulIwAlIwIZW50aXRpZXOUXZRoaYwFRmFsc2WUaCCMBGhpZ2iUjApsZW56X3Njb3JllEsCaIOMKkZpbmRpbmcgZm9yIFRoZSBFaWZmZWwgVG93ZXIgaXMgaW4gQmVybGluLpSMEWV4ZWN1dGl2ZV9zdW1tYXJ5lIwqU3VtbWFyeSBmb3IgVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulGiGjCVGaXhlZDogVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulIwId2FybmluZ3OUXZSMAncxlGFoD4wgMjAyNi0xMC0wMVQwODowMDowMC4xMjM0NTYrMDA6MDCUjAttb2RpZmllZF9hdJROaHKMLWh0dHBzOi8vbGVuei5pby9hcGkvdjEvdmVyaWZpY2F0aW9ucy82OGNhNGFhZpRodIwtaHR0cHM6Ly9sZW56LmlvL2MvdGhlLWVhcnRoLWlzLXJvdW5kLTY4Y2E0YWFmlGiITnVoKX2UaCuPlChobmhyaNhoIGjlaN5odGjTaAto1miDaGZoJWgPaGlohmjhaM9oE2jcaMxoiJBoLU51YmiJTnVoKX2UaCuPlChoZmitaHZonmjFaIlooWigkGgtTnViYYwJY2l0YXRpb25zlF2UdWgpfZRoK4+UKGiRaIxoEWgLaBVoj2heaC5olWhVaA9oUWiXaA1ok2gTaAlo7GhLaAdoiJBoLU51Yi4=", + "review__get_policy_resolved.json": "gASVlwcAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZSMBUZhbHNllGGMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsCjAVkZXB0aJSMA2xvd5SMDW1heF9jaXRhdGlvbnOUSwCMDXN1Z2dlc3RfZWRpdHOUiXWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBtoI2geaCVoJmgiaCGQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMB3N1bW1hcnmUaACMDVJldmlld1N1bW1hcnmUk5QpgZR9lChoBX2UKIwPY2xhaW1zX3NlbGVjdGVklEsBjAtjbGFpbV9saW1pdJRLFIwTY2xhaW1fbGltaXRfcmVhY2hlZJSJjA9pbnB1dF90cnVuY2F0ZWSUiYwLYXNzZXNzbWVudHOUaACMFlJldmlld0Fzc2Vzc21lbnRDb3VudHOUk5QpgZR9lChoBX2UKIwJY29tcGxldGVklEsBjAZmYWlsZWSUSwB1aCd9lGgpj5QoaDxoPZBoK051YowNdmVyaWZpY2F0aW9uc5RoAIwYUmV2aWV3VmVyaWZpY2F0aW9uQ291bnRzlJOUKYGUfZQoaAV9lCiMB3BsYW5uZWSUSwBoPEsAaD1LAHVoJ32UaCmPlChoPGg9aEaQaCtOdWKMBmlzc3Vlc5RLAIwPY2l0YXRpb25zX2ZvdW5klE6MEmNpdGF0aW9uc19zZWxlY3RlZJROjA5jaXRhdGlvbl9saW1pdJROjBZjaXRhdGlvbl9saW1pdF9yZWFjaGVklE6MD2NpdGF0aW9uX2NoZWNrc5ROjA9jaXRhdGlvbl9pc3N1ZXOUSwCMEWNpdGF0aW9uc19za2lwcGVklE51aCd9lGgpj5QoaDJoNmg1aEtoQGhQaE1oSWgzaExoT2hOaEpoNJBoK051YowHY3JlZGl0c5RoAIwNUmV2aWV3Q3JlZGl0c5STlCmBlH2UKGgFfZSMB2NoYXJnZWSUSwFzaCd9lGgpj5QoaFmQaCtOdWKMEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROaEldlIwIZmFpbHVyZXOUXZRoT12UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUXZSMFG1vcmVfY2xhaW1fbG9jYXRpb25zlF2UjA5tb3JlX2NpdGF0aW9uc5RdlIwHZmFpbHVyZZROjAZjbGFpbXOUXZRoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwCMBWNsYWltlIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpSMCXBvc2l0aW9uc5ROjAZyZXN1bHSUaACMDFJldmlld1Jlc3VsdJSTlCmBlH2UKGgFfZQojAd2ZXJkaWN0lIwEVHJ1ZZRoHowEaGlnaJSMBnNvdXJjZZSMCmFzc2Vzc21lbnSUjAhpc19pc3N1ZZSJdWgnfZRoKY+UKGgeaHtofmiAkGgrTnVijAphc3Nlc3NtZW50lGgAjBBSZXZpZXdBc3Nlc3NtZW50lJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGh7jARUcnVllGgejARoaWdolIwJcmF0aW9uYWxllE6MB2Rpc3NlbnSUTowQdmVyaWZpY2F0aW9uX3VybJROjAplcnJvcl9jb2RllE6MEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE6MEXN1Z2dlc3RlZF9yZXdyaXRllE5oaU51aCd9lGgpj5QoaJJojWiOaB5oC2h7aJBojGiPaJNoaZBoK051YowKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAtkaXNwb3NpdGlvbpSMDG5vdF9zZWxlY3RlZJR1aCd9lGgpj5QoaJ5onJBoK051YowMdmVyaWZpY2F0aW9ulE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgnfZRoKY+UKGhyaINolmhxaKJoo2h1aHSQaCtOdWJhjAljaXRhdGlvbnOUXZR1aCd9lGgpj5QoaGNoXmgRaAtoFWhhaFxoLGhnaFNoD2hPaGpoDWhlaBNoCWimaEloB2hpkGgrTnViLg==", + "review__get_queued.json": "gASVbAQAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwGcXVldWVklIwHb3V0Y29tZZROjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGWgjaB5oJWgmaCJoIZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUTowLY2xhaW1fbGltaXSUSxSME2NsYWltX2xpbWl0X3JlYWNoZWSUTowPaW5wdXRfdHJ1bmNhdGVklImMC2Fzc2Vzc21lbnRzlE6MDXZlcmlmaWNhdGlvbnOUTowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoJ32UaCmPlChoMmg2aDVoOmg3aD9oPGg4aDNoO2g+aD1oOWg0kGgrTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAHNoJ32UaCmPlChoSJBoK051YowScG9sbF9hZnRlcl9zZWNvbmRzlEsKaDhdlIwIZmFpbHVyZXOUXZRoPl2UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUTowUbW9yZV9jbGFpbV9sb2NhdGlvbnOUTowObW9yZV9jaXRhdGlvbnOUTowHZmFpbHVyZZROjAZjbGFpbXOUXZSMCWNpdGF0aW9uc5RdlHVoJ32UaCmPlChoUmhNaBBoC2gTaFBoS2gsaFRoQmgOaD5oVmgNaFNoEWgJaFhoOGgHaFWQaCtOdWIu", + "review__get_suggested_edits.json": "gASV2xEAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJdmVyaWZ5aW5nlIwHb3V0Y29tZZROjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SIdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGWgjaB5oJWgmaCJoIZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwKMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwKMBmZhaWxlZJRLAHVoJ32UaCmPlChoPGg9kGgrTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAmg8SwFoPUsAdWgnfZRoKY+UKGg8aD1oRpBoK051YowGaXNzdWVzlEsCjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoJ32UaCmPlChoMmg2aDVoS2hAaFBoTWhJaDNoTGhPaE5oSmg0kGgrTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLDHNoJ32UaCmPlChoWZBoK051YowScG9sbF9hZnRlcl9zZWNvbmRzlEsPaEldlChoAIwLUmV2aWV3SXNzdWWUk5QpgZR9lChoBX2UKIwLY2xhaW1faW5kZXiUSwCMBWNsYWltlIweVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulIwOdmVyaWZpZWRfY2xhaW2UTowHdmVyZGljdJSMBUZhbHNllGgejARoaWdolIwGc291cmNllIwMdmVyaWZpY2F0aW9ulIwPdmVyaWZpY2F0aW9uX2lklIwINjhjYTRhYWaUjBN2ZXJpZmljYXRpb25fc3RhdHVzlIwJY29tcGxldGVklIwQdmVyaWZpY2F0aW9uX3VybJSMLWh0dHBzOi8vbGVuei5pby9hcGkvdjEvdmVyaWZpY2F0aW9ucy82OGNhNGFhZpSMA3VybJSMLWh0dHBzOi8vbGVuei5pby9jL3RoZS1lYXJ0aC1pcy1yb3VuZC02OGNhNGFhZpSMCmVzY2FsYXRpb26UaACMCkVzY2FsYXRpb26Uk5QpgZR9lChoBX2UKIwNbWF0Y2hlZF9ydWxlc5RdlIwHdmVyZGljdJRhjAtkaXNwb3NpdGlvbpSMB3BsYW5uZWSUdWgnfZRoKY+UKGh9aHqQaCtOdWKMC2tleV9maW5kaW5nlIwqRmluZGluZyBmb3IgVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulIwJcmF0aW9uYWxllE6MEXN1Z2dlc3RlZF9yZXdyaXRllIwlRml4ZWQ6IFRoZSBFaWZmZWwgVG93ZXIgaXMgaW4gQmVybGluLpSMB2ZhaWx1cmWUTowPc3VnZ2VzdGVkX2VkaXRzlGgAjA5TdWdnZXN0ZWRFZGl0c5STlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJSMBWVkaXRzlF2UaACMDVN1Z2dlc3RlZEVkaXSUk5QpgZR9lChoBX2UKIwIcG9zaXRpb26USwCMBXN0YXJ0lEsXjANlbmSUSx2MBHRleHSUjAZCZXJsaW6UjAtyZXBsYWNlbWVudJSMBVBhcmlzlHVoJ32UaCmPlCholmiVaJpol2iYkGgrTnViYXVoJ32UaCmPlChojmgLkGgrTnVidWgnfZRoKY+UKGhkaGxocGgeaGdobmh0aINoh2hyaGpoZmhjaIFohGiGkGgrTnViaF8pgZR9lChoBX2UKGhjSwFoZIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpRoZk5oZ4wFRmFsc2WUaB6MBGhpZ2iUaGqMCmFzc2Vzc21lbnSUaGxOaG6MCnByb2Nlc3NpbmeUaHBOaHJOaHRodimBlH2UKGgFfZQoaHpdlIwHdmVyZGljdJRhaH2MB3BsYW5uZWSUdWgnfZRoKY+UKGh9aHqQaCtOdWJogU5og05ohE5ohk5oh2iJKYGUfZQoaAV9lChoC4wHcGVuZGluZ5Rojk51aCd9lGgpj5QoaI5oC5BoK051YnVoJ32UaCmPlChoZGhsaHBoHmhnaG5odGiDaIdocmhqaGZoY2iBaIRohpBoK051YmWMCGZhaWx1cmVzlF2UaE9dlIwRY2l0YXRpb25fZmFpbHVyZXOUXZSMC21vcmVfY2xhaW1zlF2UjBRtb3JlX2NsYWltX2xvY2F0aW9uc5RdlIwObW9yZV9jaXRhdGlvbnOUXZRohk6MBmNsYWltc5RdlChoAIwLUmV2aWV3Q2xhaW2Uk5QpgZR9lChoBX2UKIwFaW5kZXiUSwBoZIweVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulIwJcG9zaXRpb25zlF2UaACMCFBvc2l0aW9ulJOUKYGUfZQoaAV9lCholksAaJdLHmiYjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UdWgnfZRoKY+UKGiWaJdomJBoK051YmGMBnJlc3VsdJRoAIwMUmV2aWV3UmVzdWx0lJOUKYGUfZQoaAV9lChoZ4wFRmFsc2WUaB6MBGhpZ2iUaGqMDHZlcmlmaWNhdGlvbpSMCGlzX2lzc3VllIh1aCd9lGgpj5QoaB5oZ2hqaOGQaCtOdWKMCmFzc2Vzc21lbnSUaACMEFJldmlld0Fzc2Vzc21lbnSUk5QpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaGeMBUZhbHNllGgejARoaWdolGiDTowHZGlzc2VudJROaHBOjAplcnJvcl9jb2RllE6MEWlkZW50aWZpZWRfY2xhaW1zlF2UjARoaW50lE5ohE5ohk51aCd9lGgpj5QoaPFo7WhwaB5oC2hnaO9og2juaIRohpBoK051Ymh0aHYpgZR9lChoBX2UKGh6XZSMB3ZlcmRpY3SUYWh9jAdwbGFubmVklHVoJ32UaCmPlChofWh6kGgrTnVijAx2ZXJpZmljYXRpb26UaACMElJldmlld1ZlcmlmaWNhdGlvbpSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJSMDmNvbnRlbnRfc3RhdHVzlIwJYXZhaWxhYmxllGhsjAg2OGNhNGFhZpSMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJRoZIweVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulGgRjAJlbpSMCnZpc2liaWxpdHmUjAdwcml2YXRllGgjjAhzdGFuZGFyZJSMBmRvbWFpbpSMAJSMCGVudGl0aWVzlF2UaGeMBUZhbHNllGgejARoaWdolIwKbGVuel9zY29yZZRLAmiBjCpGaW5kaW5nIGZvciBUaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjBFleGVjdXRpdmVfc3VtbWFyeZSMKlN1bW1hcnkgZm9yIFRoZSBFaWZmZWwgVG93ZXIgaXMgaW4gQmVybGluLpRohIwlRml4ZWQ6IFRoZSBFaWZmZWwgVG93ZXIgaXMgaW4gQmVybGluLpSMCHdhcm5pbmdzlF2UjAJ3MZRhaA6MIDIwMjYtMTAtMDFUMDk6MTQ6MDAuMTIzNDU2KzAwOjAwlIwLbW9kaWZpZWRfYXSUTmhwjC1odHRwczovL2xlbnouaW8vYXBpL3YxL3ZlcmlmaWNhdGlvbnMvNjhjYTRhYWaUaHKMLWh0dHBzOi8vbGVuei5pby9jL3RoZS1lYXJ0aC1pcy1yb3VuZC02OGNhNGFhZpRohk51aCd9lGgpj5QoaGxocGoPAQAAaB5qHAEAAGoVAQAAaHJqCgEAAGgLag0BAABogWhkaCNoDmhnaIRqGAEAAGoGAQAAaBFqEwEAAGoDAQAAaIaQaCtOdWJoh2iJKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGiOXZRokSmBlH2UKGgFfZQoaJVLAGiWSxdol0sdaJiMBkJlcmxpbpRomowFUGFyaXOUdWgnfZRoKY+UKGiWaJVommiXaJiQaCtOdWJhdWgnfZRoKY+UKGiOaAuQaCtOdWJ1aCd9lGgpj5QoaGRo5Gh0aMxo/GiHaNhozpBoK051YmjIKYGUfZQoaAV9lChozEsBaGSMKFRoZSBFVSBBSSBBY3QgdG9vayBlZmZlY3QgaW4gTWFyY2ggMjAyNC6UaM5dlGjRKYGUfZQoaAV9lCholkstaJdLVWiYjChUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulHVoJ32UaCmPlCholmiXaJiQaCtOdWJhaNho2imBlH2UKGgFfZQoaGeMBUZhbHNllGgejARoaWdolGhqjAphc3Nlc3NtZW50lGjhiHVoJ32UaCmPlChoHmhnaGpo4ZBoK051YmjkaOYpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaGeMBUZhbHNllGgejARoaWdolGiDTmjtTmhwTmjuTmjvXZRo8U5ohE5ohk51aCd9lGgpj5QoaPFo7WhwaB5oC2hnaO9og2juaIRohpBoK051Ymh0aHYpgZR9lChoBX2UKGh6XZSMB3ZlcmRpY3SUYWh9jAdwbGFubmVklHVoJ32UaCmPlChofWh6kGgrTnViaPxo/imBlH2UKGgFfZQoaAuMCnByb2Nlc3NpbmeUagMBAACMCWF2YWlsYWJsZZRobE5qBgEAAE5oZE5oEU5qCgEAAE5oI05qDQEAAE5qDwEAAF2UaGdOaB5OahMBAABOaIFOahUBAABOaIROahgBAABdlGgOTmocAQAATmhwTmhyTmiGTnVoJ32UaCmPlChobGhwag8BAABoHmocAQAAahUBAABocmoKAQAAaAtqDQEAAGiBaGRoI2gOaGdohGoYAQAAagYBAABoEWoTAQAAagMBAABohpBoK051YmiHaIkpgZR9lChoBX2UKGgLjAdwZW5kaW5nlGiOTnVoJ32UaCmPlChojmgLkGgrTnVidWgnfZRoKY+UKGhkaORodGjMaPxoh2jYaM6QaCtOdWJljAljaXRhdGlvbnOUXZR1aCd9lGgpj5QoaL9oumgQaAtoE2i9aFxoLGjDaFNoDmhPaMVoDWjBaBFoCWpmAQAAaEloB2iGkGgrTnViLg==", + "review__get_suggested_edits_issues_view.json": "gASVmgkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjAZpc3N1ZXOUjAZzdGF0dXOUjAl2ZXJpZnlpbmeUjAdvdXRjb21llE6MCmNyZWF0ZWRfYXSUjBsyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NlqUjAxjb21wbGV0ZWRfYXSUTowIbGFuZ3VhZ2WUjAJlbpSMBnBvbGljeZRoAIwQRXNjYWxhdGlvblBvbGljeZSTlCmBlH2UKGgFfZQojAh2ZXJkaWN0c5RdlCiMBUZhbHNllIwMTW9zdGx5IEZhbHNllIwFTWl4ZWSUZYwKY29uZmlkZW5jZZRdlIwDbG93lGGMD21heF9hc3Nlc3NtZW50c5RLFIwRbWF4X3ZlcmlmaWNhdGlvbnOUSwWMBWRlcHRolIwIc3RhbmRhcmSUjA1tYXhfY2l0YXRpb25zlEsAjA1zdWdnZXN0X2VkaXRzlIh1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgZaCNoHmglaCZoImghkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAdzdW1tYXJ5lGgAjA1SZXZpZXdTdW1tYXJ5lJOUKYGUfZQoaAV9lCiMD2NsYWltc19zZWxlY3RlZJRLAowLY2xhaW1fbGltaXSUSxSME2NsYWltX2xpbWl0X3JlYWNoZWSUiYwPaW5wdXRfdHJ1bmNhdGVklImMC2Fzc2Vzc21lbnRzlGgAjBZSZXZpZXdBc3Nlc3NtZW50Q291bnRzlJOUKYGUfZQoaAV9lCiMCWNvbXBsZXRlZJRLAowGZmFpbGVklEsAdWgnfZRoKY+UKGg8aD2QaCtOdWKMDXZlcmlmaWNhdGlvbnOUaACMGFJldmlld1ZlcmlmaWNhdGlvbkNvdW50c5STlCmBlH2UKGgFfZQojAdwbGFubmVklEsCaDxLAWg9SwB1aCd9lGgpj5QoaDxoPWhGkGgrTnVijAZpc3N1ZXOUSwKMD2NpdGF0aW9uc19mb3VuZJROjBJjaXRhdGlvbnNfc2VsZWN0ZWSUTowOY2l0YXRpb25fbGltaXSUTowWY2l0YXRpb25fbGltaXRfcmVhY2hlZJROjA9jaXRhdGlvbl9jaGVja3OUTowPY2l0YXRpb25faXNzdWVzlEsAjBFjaXRhdGlvbnNfc2tpcHBlZJROdWgnfZRoKY+UKGgyaDZoNWhLaEBoUGhNaEloM2hMaE9oTmhKaDSQaCtOdWKMB2NyZWRpdHOUaACMDVJldmlld0NyZWRpdHOUk5QpgZR9lChoBX2UjAdjaGFyZ2VklEsMc2gnfZRoKY+UKGhZkGgrTnVijBJwb2xsX2FmdGVyX3NlY29uZHOUSw9oSV2UKGgAjAtSZXZpZXdJc3N1ZZSTlCmBlH2UKGgFfZQojAtjbGFpbV9pbmRleJRLAIwFY2xhaW2UjB5UaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjA52ZXJpZmllZF9jbGFpbZROjAd2ZXJkaWN0lIwFRmFsc2WUaB6MBGhpZ2iUjAZzb3VyY2WUjAx2ZXJpZmljYXRpb26UjA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSME3ZlcmlmaWNhdGlvbl9zdGF0dXOUjAljb21wbGV0ZWSUjBB2ZXJpZmljYXRpb25fdXJslIwtaHR0cHM6Ly9sZW56LmlvL2FwaS92MS92ZXJpZmljYXRpb25zLzY4Y2E0YWFmlIwDdXJslIwtaHR0cHM6Ly9sZW56LmlvL2MvdGhlLWVhcnRoLWlzLXJvdW5kLTY4Y2E0YWFmlIwKZXNjYWxhdGlvbpRoAIwKRXNjYWxhdGlvbpSTlCmBlH2UKGgFfZQojA1tYXRjaGVkX3J1bGVzlF2UjAd2ZXJkaWN0lGGMC2Rpc3Bvc2l0aW9ulIwHcGxhbm5lZJR1aCd9lGgpj5QoaH1oepBoK051YowLa2V5X2ZpbmRpbmeUjCpGaW5kaW5nIGZvciBUaGUgRWlmZmVsIFRvd2VyIGlzIGluIEJlcmxpbi6UjAlyYXRpb25hbGWUTowRc3VnZ2VzdGVkX3Jld3JpdGWUjCVGaXhlZDogVGhlIEVpZmZlbCBUb3dlciBpcyBpbiBCZXJsaW4ulIwHZmFpbHVyZZROjA9zdWdnZXN0ZWRfZWRpdHOUaACMDlN1Z2dlc3RlZEVkaXRzlJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklIwFZWRpdHOUXZRoAIwNU3VnZ2VzdGVkRWRpdJSTlCmBlH2UKGgFfZQojAhwb3NpdGlvbpRLAIwFc3RhcnSUSxeMA2VuZJRLHYwEdGV4dJSMBkJlcmxpbpSMC3JlcGxhY2VtZW50lIwFUGFyaXOUdWgnfZRoKY+UKGiWaJVommiXaJiQaCtOdWJhdWgnfZRoKY+UKGiOaAuQaCtOdWJ1aCd9lGgpj5QoaGRobGhwaB5oZ2huaHRog2iHaHJoamhmaGNogWiEaIaQaCtOdWJoXymBlH2UKGgFfZQoaGNLAWhkjChUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulGhmTmhnjAVGYWxzZZRoHowEaGlnaJRoaowKYXNzZXNzbWVudJRobE5obowKcHJvY2Vzc2luZ5RocE5ock5odGh2KYGUfZQoaAV9lChoel2UjAd2ZXJkaWN0lGFofYwHcGxhbm5lZJR1aCd9lGgpj5QoaH1oepBoK051YmiBTmiDTmiETmiGTmiHaIkpgZR9lChoBX2UKGgLjAdwZW5kaW5nlGiOTnVoJ32UaCmPlChojmgLkGgrTnVidWgnfZRoKY+UKGhkaGxocGgeaGdobmh0aINoh2hyaGpoZmhjaIFohGiGkGgrTnViZYwIZmFpbHVyZXOUXZRoT12UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUXZSMFG1vcmVfY2xhaW1fbG9jYXRpb25zlF2UjA5tb3JlX2NpdGF0aW9uc5RdlGiGTowGY2xhaW1zlF2UjAljaXRhdGlvbnOUXZR1aCd9lGgpj5QoaL9oumgQaAtoE2i9aFxoLGjDaFNoDmhPaA1owWgRaAloSWgHaIaQaCtOdWIu", + "review__get_url_review.json": "gASVKAgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJY29tcGxldGVklIwHb3V0Y29tZZSMBWNsZWFulIwKY3JlYXRlZF9hdJSMGzIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2WpSMDGNvbXBsZXRlZF9hdJSMGzIwMjYtMTAtMDFUMTA6MDc6MDAuMTIzNDU2WpSMCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoG2glaCBoJ2goaCRoI5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwGMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwGMBmZhaWxlZJRLAHVoKX2UaCuPlChoPmg/kGgtTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAGg+SwBoP0sAdWgpfZRoK4+UKGg+aD9oSJBoLU51YowGaXNzdWVzlEsAjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoKX2UaCuPlChoNGg4aDdoTWhCaFJoT2hLaDVoTmhRaFBoTGg2kGgtTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAXNoKX2UaCuPlChoW5BoLU51YowScG9sbF9hZnRlcl9zZWNvbmRzlE5oS12UjAhmYWlsdXJlc5RdlGhRXZSMEWNpdGF0aW9uX2ZhaWx1cmVzlF2UjAttb3JlX2NsYWltc5RdlIwUbW9yZV9jbGFpbV9sb2NhdGlvbnOUXZSMDm1vcmVfY2l0YXRpb25zlF2UjAdmYWlsdXJllE6MBmNsYWltc5RdlGgAjAtSZXZpZXdDbGFpbZSTlCmBlH2UKGgFfZQojAVpbmRleJRLAIwFY2xhaW2UjChUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulIwJcG9zaXRpb25zlF2UaACMCFBvc2l0aW9ulJOUKYGUfZQoaAV9lCiMBXN0YXJ0lE6MA2VuZJROjAR0ZXh0lIwoVGhlIEVVIEFJIEFjdCB0b29rIGVmZmVjdCBpbiBNYXJjaCAyMDI0LpR1aCl9lGgrj5QoaH1ofmh/kGgtTnViYYwGcmVzdWx0lGgAjAxSZXZpZXdSZXN1bHSUk5QpgZR9lChoBX2UKIwHdmVyZGljdJSMBFRydWWUaCCMBGhpZ2iUjAZzb3VyY2WUjAphc3Nlc3NtZW50lIwIaXNfaXNzdWWUiXVoKX2UaCuPlChoIGiJaIxojpBoLU51YowKYXNzZXNzbWVudJRoAIwQUmV2aWV3QXNzZXNzbWVudJSTlCmBlH2UKGgFfZQoaAuMCWNvbXBsZXRlZJRoiYwEVHJ1ZZRoIIwEaGlnaJSMCXJhdGlvbmFsZZROjAdkaXNzZW50lE6MEHZlcmlmaWNhdGlvbl91cmyUTowKZXJyb3JfY29kZZROjBFpZGVudGlmaWVkX2NsYWltc5RdlIwEaGludJROjBFzdWdnZXN0ZWRfcmV3cml0ZZROaGtOdWgpfZRoK4+UKGigaJtonGggaAtoiWieaJponWihaGuQaC1OdWKMCmVzY2FsYXRpb26UaACMCkVzY2FsYXRpb26Uk5QpgZR9lChoBX2UKIwNbWF0Y2hlZF9ydWxlc5RdlIwLZGlzcG9zaXRpb26UjAxub3Rfc2VsZWN0ZWSUdWgpfZRoK4+UKGisaKqQaC1OdWKMDHZlcmlmaWNhdGlvbpROjA9zdWdnZXN0ZWRfZWRpdHOUTnVoKX2UaCuPlChodGiRaKRoc2iwaLFog2h2kGgtTnViYYwJY2l0YXRpb25zlF2UdWgpfZRoK4+UKGhlaGBoEWgLaBVoY2heaC5oaWhVaA9oUWhsaA1oZ2gTaAlotGhLaAdoa5BoLU51Yi4=", + "review__get_verifying.json": "gASVYgsAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKUmV2aWV3RnVsbJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBHZpZXeUjARmdWxslIwGc3RhdHVzlIwJdmVyaWZ5aW5nlIwHb3V0Y29tZZROjApjcmVhdGVkX2F0lIwbMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTZalIwMY29tcGxldGVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAZwb2xpY3mUaACMEEVzY2FsYXRpb25Qb2xpY3mUk5QpgZR9lChoBX2UKIwIdmVyZGljdHOUXZQojAVGYWxzZZSMDE1vc3RseSBGYWxzZZSMBU1peGVklGWMCmNvbmZpZGVuY2WUXZSMA2xvd5RhjA9tYXhfYXNzZXNzbWVudHOUSxSMEW1heF92ZXJpZmljYXRpb25zlEsFjAVkZXB0aJSMCHN0YW5kYXJklIwNbWF4X2NpdGF0aW9uc5RLAIwNc3VnZ2VzdF9lZGl0c5SJdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGWgjaB5oJWgmaCJoIZCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YowHc3VtbWFyeZRoAIwNUmV2aWV3U3VtbWFyeZSTlCmBlH2UKGgFfZQojA9jbGFpbXNfc2VsZWN0ZWSUSwKMC2NsYWltX2xpbWl0lEsUjBNjbGFpbV9saW1pdF9yZWFjaGVklImMD2lucHV0X3RydW5jYXRlZJSJjAthc3Nlc3NtZW50c5RoAIwWUmV2aWV3QXNzZXNzbWVudENvdW50c5STlCmBlH2UKGgFfZQojAljb21wbGV0ZWSUSwKMBmZhaWxlZJRLAHVoJ32UaCmPlChoPGg9kGgrTnVijA12ZXJpZmljYXRpb25zlGgAjBhSZXZpZXdWZXJpZmljYXRpb25Db3VudHOUk5QpgZR9lChoBX2UKIwHcGxhbm5lZJRLAWg8SwBoPUsAdWgnfZRoKY+UKGg8aD1oRpBoK051YowGaXNzdWVzlEsBjA9jaXRhdGlvbnNfZm91bmSUTowSY2l0YXRpb25zX3NlbGVjdGVklE6MDmNpdGF0aW9uX2xpbWl0lE6MFmNpdGF0aW9uX2xpbWl0X3JlYWNoZWSUTowPY2l0YXRpb25fY2hlY2tzlE6MD2NpdGF0aW9uX2lzc3Vlc5RLAIwRY2l0YXRpb25zX3NraXBwZWSUTnVoJ32UaCmPlChoMmg2aDVoS2hAaFBoTWhJaDNoTGhPaE5oSmg0kGgrTnVijAdjcmVkaXRzlGgAjA1SZXZpZXdDcmVkaXRzlJOUKYGUfZQoaAV9lIwHY2hhcmdlZJRLAnNoJ32UaCmPlChoWZBoK051YowScG9sbF9hZnRlcl9zZWNvbmRzlEsPaEldlGgAjAtSZXZpZXdJc3N1ZZSTlCmBlH2UKGgFfZQojAtjbGFpbV9pbmRleJRLAIwFY2xhaW2UjChUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulIwOdmVyaWZpZWRfY2xhaW2UTowHdmVyZGljdJSMBUZhbHNllGgejARoaWdolIwGc291cmNllIwKYXNzZXNzbWVudJSMD3ZlcmlmaWNhdGlvbl9pZJROjBN2ZXJpZmljYXRpb25fc3RhdHVzlIwKcHJvY2Vzc2luZ5SMEHZlcmlmaWNhdGlvbl91cmyUTowDdXJslE6MCmVzY2FsYXRpb26UaACMCkVzY2FsYXRpb26Uk5QpgZR9lChoBX2UKIwNbWF0Y2hlZF9ydWxlc5RdlIwHdmVyZGljdJRhjAtkaXNwb3NpdGlvbpSMB3BsYW5uZWSUdWgnfZRoKY+UKGh6aHeQaCtOdWKMC2tleV9maW5kaW5nlE6MCXJhdGlvbmFsZZROjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdmYWlsdXJllE6MD3N1Z2dlc3RlZF9lZGl0c5ROdWgnfZRoKY+UKGhkaGxob2geaGdobWhxaH9ogmhwaGpoZmhjaH5ogGiBkGgrTnViYYwIZmFpbHVyZXOUXZRoT12UjBFjaXRhdGlvbl9mYWlsdXJlc5RdlIwLbW9yZV9jbGFpbXOUXZSMFG1vcmVfY2xhaW1fbG9jYXRpb25zlF2UjA5tb3JlX2NpdGF0aW9uc5RdlGiBTowGY2xhaW1zlF2UKGgAjAtSZXZpZXdDbGFpbZSTlCmBlH2UKGgFfZQojAVpbmRleJRLAGhkjChUaGUgRVUgQUkgQWN0IHRvb2sgZWZmZWN0IGluIE1hcmNoIDIwMjQulIwJcG9zaXRpb25zlE6MBnJlc3VsdJRoAIwMUmV2aWV3UmVzdWx0lJOUKYGUfZQoaAV9lChoZ4wFRmFsc2WUaB6MBGhpZ2iUaGqMCmFzc2Vzc21lbnSUjAhpc19pc3N1ZZSIdWgnfZRoKY+UKGgeaGdoamijkGgrTnVijAphc3Nlc3NtZW50lGgAjBBSZXZpZXdBc3Nlc3NtZW50lJOUKYGUfZQoaAV9lChoC4wJY29tcGxldGVklGhnjAVGYWxzZZRoHowEaGlnaJRof06MB2Rpc3NlbnSUTmhvTowKZXJyb3JfY29kZZROjBFpZGVudGlmaWVkX2NsYWltc5RdlIwEaGludJROaIBOaIFOdWgnfZRoKY+UKGizaK9ob2geaAtoZ2ixaH9osGiAaIGQaCtOdWJocWhzKYGUfZQoaAV9lChod12UjAd2ZXJkaWN0lGFoeowHcGxhbm5lZJR1aCd9lGgpj5QoaHpod5BoK051YowMdmVyaWZpY2F0aW9ulGgAjBJSZXZpZXdWZXJpZmljYXRpb26Uk5QpgZR9lChoBX2UKGgLjApwcm9jZXNzaW5nlIwOY29udGVudF9zdGF0dXOUjAlhdmFpbGFibGWUaGxOjAd0YXNrX2lklE5oZE5oEU6MCnZpc2liaWxpdHmUTmgjTowGZG9tYWlulE6MCGVudGl0aWVzlF2UaGdOaB5OjApsZW56X3Njb3JllE5ofk6MEWV4ZWN1dGl2ZV9zdW1tYXJ5lE5ogE6MCHdhcm5pbmdzlF2UaA5OjAttb2RpZmllZF9hdJROaG9OaHBOaIFOdWgnfZRoKY+UKGhsaG9oymgeaNBozWhwaMhoC2jJaH5oZGgjaA5oZ2iAaM5ox2gRaMxoxWiBkGgrTnViaIJOdWgnfZRoKY+UKGhkaKZocWiXaL5ogmiaaJmQaCtOdWJokymBlH2UKGgFfZQoaJdLAWhkjCJXYXRlciBib2lscyBhdCAxMDAgQyBhdCBzZWEgbGV2ZWwulGiZTmiaaJwpgZR9lChoBX2UKGhnjARUcnVllGgejARoaWdolGhqjAphc3Nlc3NtZW50lGijiXVoJ32UaCmPlChoHmhnaGpoo5BoK051YmimaKgpgZR9lChoBX2UKGgLjAljb21wbGV0ZWSUaGeMBFRydWWUaB6MBGhpZ2iUaH9OaK9OaG9OaLBOaLFdlGizTmiATmiBTnVoJ32UaCmPlChos2ivaG9oHmgLaGdosWh/aLBogGiBkGgrTnViaHFocymBlH2UKGgFfZQoaHddlGh6jAxub3Rfc2VsZWN0ZWSUdWgnfZRoKY+UKGh6aHeQaCtOdWJovk5ogk51aCd9lGgpj5QoaGRopmhxaJdovmiCaJpomZBoK051YmWMCWNpdGF0aW9uc5RdlHVoJ32UaCmPlChoimiFaBBoC2gTaIhoXGgsaI5oU2gOaE9okGgNaIxoEWgJaPNoSWgHaIGQaCtOdWIu", + "review__idempotent_replay_202.json": "gASVtQAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwNUmV2aWV3U3RhcnRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBnN0YXR1c5SMBnF1ZXVlZJR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgJaAeQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "review__receipt_202.json": "gASVtQAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwNUmV2aWV3U3RhcnRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBnN0YXR1c5SMBnF1ZXVlZJR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgJaAeQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "review__receipt_202_empty_webhook_url.json": "gASVtQAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwNUmV2aWV3U3RhcnRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBnN0YXR1c5SMBnF1ZXVlZJR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgJaAeQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "review__receipt_202_webhook_url.json": "gASVtQAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwNUmV2aWV3U3RhcnRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBnN0YXR1c5SMBnF1ZXVlZJR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgJaAeQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "review__replay_later_202.json": "gASVtQAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwNUmV2aWV3U3RhcnRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAlyZXZpZXdfaWSUjAhkNmIyYmQ3MpSMBnN0YXR1c5SMBnF1ZXVlZJR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgJaAeQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "verify__batch_202.json": "gASVpAEAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwNQmF0Y2hBY2NlcHRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAhiYXRjaF9pZJSMEDdlYTljZGJkNDA2NGUzY2aUjAVpdGVtc5RdlChoAIwMVGFza0FjY2VwdGVklJOUKYGUfZQoaAV9lCiMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJSMCmNsYWltX3RleHSUjBNUaGUgRWFydGggaXMgcm91bmQulHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBJoEJCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmgMKYGUfZQoaAV9lChoEIwgMGI5MmI0NDNlYjY5YjljNzE0MzRmZGM2NGYyY2E4YmWUaBKMIVdhdGVyIGJvaWxzIGF0IDEwMEMgYXQgc2VhIGxldmVsLpR1aBR9lGgWj5QoaBJoEJBoGE51YmV1aBR9lGgWj5QoaAdoCZBoGE51Yi4=", + "verify__batch_partial_202.json": "gASVPgEAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwNQmF0Y2hBY2NlcHRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAhiYXRjaF9pZJSMEDdlYTljZGJkNDA2NGUzY2aUjAVpdGVtc5RdlGgAjAxUYXNrQWNjZXB0ZWSUk5QpgZR9lChoBX2UKIwHdGFza19pZJSMIDdjZmYxOGRhMmQ5NzlkNjM3MGU1NGExNjBiZTEyMWFklIwKY2xhaW1fdGV4dJSMDEZpcnN0IGNsYWltLpR1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgSaBCQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJhdWgUfZSMB3BhcnRpYWyUiHNoFo+UKGgHaBpoCZBoGE51Yi4=", + "verify__delete_200.json": "gASVrAAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVGFza0FjY2VwdGVklJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMB3Rhc2tfaWSUjACUjApjbGFpbV90ZXh0lGgIdYwSX19weWRhbnRpY19leHRyYV9flH2UjAJva5SIc4wXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaAyQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "verify__idempotency_key_replay.json": "gASV/AAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVGFza0FjY2VwdGVklJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJSMCmNsYWltX3RleHSUjACUdYwSX19weWRhbnRpY19leHRyYV9flH2UKIwGc3RhdHVzlIwGcXVldWVklIwIY2hhaW5faWSUjBA5OWEwYTljYTg5ZTFlNzJjlHWMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgPaA1oB5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51Yi4=", + "verify__implicit_dedup_200.json": "gASV2wAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVGFza0FjY2VwdGVklJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJSMCmNsYWltX3RleHSUjACUdYwSX19weWRhbnRpY19leHRyYV9flH2UjAZzdGF0dXOUjAZxdWV1ZWSUc4wXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaA1oB5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51Yi4=", + "verify__implicit_repeat_replay.json": "gASV/AAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVGFza0FjY2VwdGVklJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJSMCmNsYWltX3RleHSUjACUdYwSX19weWRhbnRpY19leHRyYV9flH2UKIwGc3RhdHVzlIwGcXVldWVklIwIY2hhaW5faWSUjBA5OWEwYTljYTg5ZTFlNzJjlHWMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgPaA1oB5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51Yi4=", + "verify__list_200.json": "gASVcQMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwQVmVyaWZpY2F0aW9uTGlzdJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAVpdGVtc5RdlChoAIwUVmVyaWZpY2F0aW9uTGlzdEl0ZW2Uk5QpgZR9lChoBX2UKIwPdmVyaWZpY2F0aW9uX2lklIwINjhjYTRhYWaUjAVjbGFpbZSME1RoZSBFYXJ0aCBpcyByb3VuZC6UjAZkb21haW6UjAdTY2llbmNllIwIZW50aXRpZXOUXZSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjBFzdWdnZXN0ZWRfcmV3cml0ZZROjApjcmVhdGVkX2F0lIwgMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTYrMDA6MDCUjAttb2RpZmllZF9hdJROjAhsYW5ndWFnZZSMAmVulHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBBoDmgUaBhoIGgSaBZoI2giaB1oGmgbaB+QjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJoCimBlH2UKGgFfZQoaA6MCDRkNDRkZmFmlGgQjBNUaGUgRWFydGggaXMgcm91bmQulGgSjAdTY2llbmNllGgUXZRoFowEVHJ1ZZRoGIwEaGlnaJRoGksJaBuMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UaB2MFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UaB9OaCCMIDIwMjYtMTAtMDFUMDk6MTQ6MDAuMTIzNDU2KzAwOjAwlGgiTmgjjAJlbpR1aCV9lGgnj5QoaBBoDmgUaBhoIGgSaBZoI2giaB1oGmgbaB+QaClOdWJljAV0b3RhbJRLAowEcGFnZZRLAYwJcGFnZV9zaXpllEsUdWglfZRoJ4+UKGg6aDtoOWgHkGgpTnViLg==", + "verify__list_200_modified_at_crosses_midnight_by_minutes.json": "gASVkAIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwQVmVyaWZpY2F0aW9uTGlzdJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAVpdGVtc5RdlGgAjBRWZXJpZmljYXRpb25MaXN0SXRlbZSTlCmBlH2UKGgFfZQojA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSMBWNsYWltlIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMBmRvbWFpbpSMB1NjaWVuY2WUjAhlbnRpdGllc5RdlIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwEaGlnaJSMCmxlbnpfc2NvcmWUSwmMC2tleV9maW5kaW5nlIwuVGhlIEVhcnRoIGlzIGFwcHJveGltYXRlbHkgc3BoZXJpY2FsIGluIHNoYXBlLpSMEWV4ZWN1dGl2ZV9zdW1tYXJ5lIwWVGhlIGNsYWltIGlzIHZlcmlmaWVkLpSMEXN1Z2dlc3RlZF9yZXdyaXRllE6MCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDIzOjU1OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lIwgMjAyNi0xMC0wMlQwMDowMzowMC4xMjM0NTYrMDA6MDCUjAhsYW5ndWFnZZSMAmVulHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBBoDmgUaBhoIGgSaBZoJGgiaB1oGmgbaB+QjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWJhjAV0b3RhbJRLAYwEcGFnZZRLAYwJcGFnZV9zaXpllEsUdWgmfZRoKI+UKGgsaC1oK2gHkGgqTnViLg==", + "verify__list_200_modified_at_same_day_hours_apart.json": "gASVbgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwQVmVyaWZpY2F0aW9uTGlzdJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAVpdGVtc5RdlGgAjBRWZXJpZmljYXRpb25MaXN0SXRlbZSTlCmBlH2UKGgFfZQojA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSMBWNsYWltlIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMBmRvbWFpbpSMB1NjaWVuY2WUjAhlbnRpdGllc5RdlIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwEaGlnaJSMCmxlbnpfc2NvcmWUSwmMC2tleV9maW5kaW5nlIwuVGhlIEVhcnRoIGlzIGFwcHJveGltYXRlbHkgc3BoZXJpY2FsIGluIHNoYXBlLpSMEWV4ZWN1dGl2ZV9zdW1tYXJ5lIwWVGhlIGNsYWltIGlzIHZlcmlmaWVkLpSMEXN1Z2dlc3RlZF9yZXdyaXRllE6MCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA4OjAwOjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoEGgOaBRoGGggaBJoFmgjaCJoHWgaaBtoH5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMBXRvdGFslEsBjARwYWdllEsBjAlwYWdlX3NpemWUSxR1aCV9lGgnj5QoaCtoLGgqaAeQaClOdWIu", + "verify__list_clamped_200.json": "gASVvgAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwQVmVyaWZpY2F0aW9uTGlzdJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAVpdGVtc5RdlIwFdG90YWyUSwCMBHBhZ2WUSwGMCXBhZ2Vfc2l6ZZRLZHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaApoC2gJaAeQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "verify__list_empty_200.json": "gASVvgAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwQVmVyaWZpY2F0aW9uTGlzdJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAVpdGVtc5RdlIwFdG90YWyUSwCMBHBhZ2WUSwGMCXBhZ2Vfc2l6ZZRLFHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaApoC2gJaAeQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWIu", + "verify__list_page2_200.json": "gASVbgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwQVmVyaWZpY2F0aW9uTGlzdJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAVpdGVtc5RdlGgAjBRWZXJpZmljYXRpb25MaXN0SXRlbZSTlCmBlH2UKGgFfZQojA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSMBWNsYWltlIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMBmRvbWFpbpSMB1NjaWVuY2WUjAhlbnRpdGllc5RdlIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwEaGlnaJSMCmxlbnpfc2NvcmWUSwmMC2tleV9maW5kaW5nlIwuVGhlIEVhcnRoIGlzIGFwcHJveGltYXRlbHkgc3BoZXJpY2FsIGluIHNoYXBlLpSMEWV4ZWN1dGl2ZV9zdW1tYXJ5lIwWVGhlIGNsYWltIGlzIHZlcmlmaWVkLpSMEXN1Z2dlc3RlZF9yZXdyaXRllE6MCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoEGgOaBRoGGggaBJoFmgjaCJoHWgaaBtoH5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMBXRvdGFslEsDjARwYWdllEsCjAlwYWdlX3NpemWUSwJ1aCV9lGgnj5QoaCtoLGgqaAeQaClOdWIu", + "verify__replay_later_202.json": "gASV/AAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVGFza0FjY2VwdGVklJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJSMCmNsYWltX3RleHSUjACUdYwSX19weWRhbnRpY19leHRyYV9flH2UKIwGc3RhdHVzlIwGcXVldWVklIwIY2hhaW5faWSUjBA5OWEwYTljYTg5ZTFlNzJjlHWMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgPaA1oB5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51Yi4=", + "verify__select_202.json": "gASVpAEAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwNQmF0Y2hBY2NlcHRlZJSTlCmBlH2UKIwIX19kaWN0X1+UfZQojAhiYXRjaF9pZJSMEDdlYTljZGJkNDA2NGUzY2aUjAVpdGVtc5RdlChoAIwMVGFza0FjY2VwdGVklJOUKYGUfZQoaAV9lCiMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJSMCmNsYWltX3RleHSUjBNUaGUgRWFydGggaXMgcm91bmQulHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBJoEJCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmgMKYGUfZQoaAV9lChoEIwgMGI5MmI0NDNlYjY5YjljNzE0MzRmZGM2NGYyY2E4YmWUaBKMIVdhdGVyIGJvaWxzIGF0IDEwMEMgYXQgc2VhIGxldmVsLpR1aBR9lGgWj5QoaBJoEJBoGE51YmV1aBR9lGgWj5QoaAdoCZBoGE51Yi4=", + "verify__status_cancelled_after_a_while.json": "gASVNgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAZmYWlsZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUjApDYW5jZWxsZWQulIwOZmFpbHVyZV9yZWFzb26UjAljYW5jZWxsZWSUjA5mYWlsdXJlX2RldGFpbJRoDIwNZmFpbHVyZV9jbGFzc5SMCWNhbmNlbGxlZJSMCXJldHJ5YWJsZZSJjAhkb2NzX3VybJSMJWh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyNjYW5jZWxsZWSUdWgZfZRoG4+UKGgJaAdoJ2gtaCpoLGglkGgdTnViLg==", + "verify__status_completed.json": "gASV5wkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAljb21wbGV0ZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUaACMDFZlcmlmaWNhdGlvbpSTlCmBlH2UKGgFfZQojA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSMBWNsYWltlIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMCnZpc2liaWxpdHmUjAdwcml2YXRllIwFZGVwdGiUjAhzdGFuZGFyZJSMBmRvbWFpbpSMB1NjaWVuY2WUjAhlbnRpdGllc5RdlGgAjAlFbnRpdHlSZWaUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUVhcnRolIwDcWlklE51aBl9lGgbj5QoaDVoN5BoHU51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoGX2UaBuPlChoUGhYaFRoUmhWkGgdTnViaEwpgZR9lChoBX2UKGhQjANFU0GUaFKMEEVhcnRoIGZyb20gc3BhY2WUaFSMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaFaMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaFiMCjIwMjUtMDEtMTaUdWgZfZRoG4+UKGhQaFhoVGhSaFaQaB1OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoRV2UdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJocSmBlH2UKGgFfZQoaHWMClJldmlld2VyIEKUaHeMB1NvdXJjZXOUaHlHQCIAAAAAAABoeowXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaEVdlIwNd2VhayBzb3VyY2UgQZRhdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoGX2UaBuPlChokWiTaI+QaB1OdWKMCmRlYmF0ZV9jb26UaIspgZR9lChoBX2UKGiPjAdTa2VwdGljlGiRjCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGiTjCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBl9lGgbj5QoaJFok2iPkGgdTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgZfZRoG4+UKGhuaJdobGigaImQaB1OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKGgHjAl1bmNvdmVyZWSUjAdyZWFzb25zlF2UjARwbGFulGGMDmNlcnRpZmljYXRlX2lklE6MD2NlcnRpZmljYXRlX3VybJROjAVhc19vZpROjAhjdXJyZW5jeZSMA0VVUpSMA2NhcJRNECeMCWFnZ3JlZ2F0ZZRKIKEHAIwNdGVybXNfdmVyc2lvbpSMAnYxlHVoGX2UaBuPlChouWi0aLhotWgHaLZoumizaLCQaB1OdWJ1aBl9lGgbj5QoaCRoLmg+aKZoQ2goaCxoQWgmaCpopGg8aDpoSGhFaKdoqWhJaGZoQJBoHU51YowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUaAyMDmZhaWx1cmVfcmVhc29ulGgMjA5mYWlsdXJlX2RldGFpbJRoDIwNZmFpbHVyZV9jbGFzc5RoDIwJcmV0cnlhYmxllE6MCGRvY3NfdXJslGgMdWgZfZRoG4+UKGgeaAdoCZBoHU51Yi4=", + "verify__status_completed_after_a_while.json": "gASV5wkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAljb21wbGV0ZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUaACMDFZlcmlmaWNhdGlvbpSTlCmBlH2UKGgFfZQojA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSMBWNsYWltlIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMCnZpc2liaWxpdHmUjAdwcml2YXRllIwFZGVwdGiUjAhzdGFuZGFyZJSMBmRvbWFpbpSMB1NjaWVuY2WUjAhlbnRpdGllc5RdlGgAjAlFbnRpdHlSZWaUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUVhcnRolIwDcWlklE51aBl9lGgbj5QoaDVoN5BoHU51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoGX2UaBuPlChoUGhYaFRoUmhWkGgdTnViaEwpgZR9lChoBX2UKGhQjANFU0GUaFKMEEVhcnRoIGZyb20gc3BhY2WUaFSMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaFaMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaFiMCjIwMjUtMDEtMTaUdWgZfZRoG4+UKGhQaFhoVGhSaFaQaB1OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoRV2UdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJocSmBlH2UKGgFfZQoaHWMClJldmlld2VyIEKUaHeMB1NvdXJjZXOUaHlHQCIAAAAAAABoeowXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaEVdlIwNd2VhayBzb3VyY2UgQZRhdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoGX2UaBuPlChokWiTaI+QaB1OdWKMCmRlYmF0ZV9jb26UaIspgZR9lChoBX2UKGiPjAdTa2VwdGljlGiRjCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGiTjCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBl9lGgbj5QoaJFok2iPkGgdTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgZfZRoG4+UKGhuaJdobGigaImQaB1OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKGgHjAl1bmNvdmVyZWSUjAdyZWFzb25zlF2UjARwbGFulGGMDmNlcnRpZmljYXRlX2lklE6MD2NlcnRpZmljYXRlX3VybJROjAVhc19vZpROjAhjdXJyZW5jeZSMA0VVUpSMA2NhcJRNECeMCWFnZ3JlZ2F0ZZRKIKEHAIwNdGVybXNfdmVyc2lvbpSMAnYxlHVoGX2UaBuPlChouWi0aLhotWgHaLZoumizaLCQaB1OdWJ1aBl9lGgbj5QoaCRoLmg+aKZoQ2goaCxoQWgmaCpopGg8aDpoSGhFaKdoqWhJaGZoQJBoHU51YowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUaAyMDmZhaWx1cmVfcmVhc29ulGgMjA5mYWlsdXJlX2RldGFpbJRoDIwNZmFpbHVyZV9jbGFzc5RoDIwJcmV0cnlhYmxllE6MCGRvY3NfdXJslGgMdWgZfZRoG4+UKGgeaAdoCZBoHU51Yi4=", + "verify__status_completed_after_a_while_modified_at_crosses_midnight_by_minutes.json": "gASVCQoAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAljb21wbGV0ZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUaACMDFZlcmlmaWNhdGlvbpSTlCmBlH2UKGgFfZQojA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSMBWNsYWltlIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMCnZpc2liaWxpdHmUjAdwcml2YXRllIwFZGVwdGiUjAhzdGFuZGFyZJSMBmRvbWFpbpSMB1NjaWVuY2WUjAhlbnRpdGllc5RdlGgAjAlFbnRpdHlSZWaUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUVhcnRolIwDcWlklE51aBl9lGgbj5QoaDVoN5BoHU51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoGX2UaBuPlChoUGhYaFRoUmhWkGgdTnViaEwpgZR9lChoBX2UKGhQjANFU0GUaFKMEEVhcnRoIGZyb20gc3BhY2WUaFSMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaFaMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaFiMCjIwMjUtMDEtMTaUdWgZfZRoG4+UKGhQaFhoVGhSaFaQaB1OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoRV2UdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJocSmBlH2UKGgFfZQoaHWMClJldmlld2VyIEKUaHeMB1NvdXJjZXOUaHlHQCIAAAAAAABoeowXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaEVdlIwNd2VhayBzb3VyY2UgQZRhdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoGX2UaBuPlChokWiTaI+QaB1OdWKMCmRlYmF0ZV9jb26UaIspgZR9lChoBX2UKGiPjAdTa2VwdGljlGiRjCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGiTjCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBl9lGgbj5QoaJFok2iPkGgdTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgZfZRoG4+UKGhuaJdobGigaImQaB1OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDIzOjU1OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lIwgMjAyNi0xMC0wMlQwMDowMzowMC4xMjM0NTYrMDA6MDCUjAhsYW5ndWFnZZSMAmVulIwIY292ZXJhZ2WUaACMCENvdmVyYWdllJOUKYGUfZQoaAV9lChoB4wJdW5jb3ZlcmVklIwHcmVhc29uc5RdlIwEcGxhbpRhjA5jZXJ0aWZpY2F0ZV9pZJROjA9jZXJ0aWZpY2F0ZV91cmyUTowFYXNfb2aUTowIY3VycmVuY3mUjANFVVKUjANjYXCUTRAnjAlhZ2dyZWdhdGWUSiChBwCMDXRlcm1zX3ZlcnNpb26UjAJ2MZR1aBl9lGgbj5QoaLpotWi5aLZoB2i3aLtotGixkGgdTnVidWgZfZRoG4+UKGgkaC5oPmimaENoKGgsaEFoJmgqaKRoPGg6aEhoRWioaKpoSWhmaECQaB1OdWKMBmNsYWltc5RdlIwKY2FuZGlkYXRlc5RdlIwOc2ltaWxhcl9jbGFpbXOUXZSMBWVycm9ylGgMjA5mYWlsdXJlX3JlYXNvbpRoDIwOZmFpbHVyZV9kZXRhaWyUaAyMDWZhaWx1cmVfY2xhc3OUaAyMCXJldHJ5YWJsZZROjAhkb2NzX3VybJRoDHVoGX2UaBuPlChoHmgHaAmQaB1OdWIu", + "verify__status_completed_after_a_while_modified_at_same_day_hours_apart.json": "gASV5wkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAljb21wbGV0ZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUaACMDFZlcmlmaWNhdGlvbpSTlCmBlH2UKGgFfZQojA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSMBWNsYWltlIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMCnZpc2liaWxpdHmUjAdwcml2YXRllIwFZGVwdGiUjAhzdGFuZGFyZJSMBmRvbWFpbpSMB1NjaWVuY2WUjAhlbnRpdGllc5RdlGgAjAlFbnRpdHlSZWaUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUVhcnRolIwDcWlklE51aBl9lGgbj5QoaDVoN5BoHU51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoGX2UaBuPlChoUGhYaFRoUmhWkGgdTnViaEwpgZR9lChoBX2UKGhQjANFU0GUaFKMEEVhcnRoIGZyb20gc3BhY2WUaFSMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaFaMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaFiMCjIwMjUtMDEtMTaUdWgZfZRoG4+UKGhQaFhoVGhSaFaQaB1OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoRV2UdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJocSmBlH2UKGgFfZQoaHWMClJldmlld2VyIEKUaHeMB1NvdXJjZXOUaHlHQCIAAAAAAABoeowXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaEVdlIwNd2VhayBzb3VyY2UgQZRhdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoGX2UaBuPlChokWiTaI+QaB1OdWKMCmRlYmF0ZV9jb26UaIspgZR9lChoBX2UKGiPjAdTa2VwdGljlGiRjCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGiTjCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBl9lGgbj5QoaJFok2iPkGgdTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgZfZRoG4+UKGhuaJdobGigaImQaB1OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA4OjAwOjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKGgHjAl1bmNvdmVyZWSUjAdyZWFzb25zlF2UjARwbGFulGGMDmNlcnRpZmljYXRlX2lklE6MD2NlcnRpZmljYXRlX3VybJROjAVhc19vZpROjAhjdXJyZW5jeZSMA0VVUpSMA2NhcJRNECeMCWFnZ3JlZ2F0ZZRKIKEHAIwNdGVybXNfdmVyc2lvbpSMAnYxlHVoGX2UaBuPlChouWi0aLhotWgHaLZoumizaLCQaB1OdWJ1aBl9lGgbj5QoaCRoLmg+aKZoQ2goaCxoQWgmaCpopGg8aDpoSGhFaKdoqWhJaGZoQJBoHU51YowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUaAyMDmZhaWx1cmVfcmVhc29ulGgMjA5mYWlsdXJlX2RldGFpbJRoDIwNZmFpbHVyZV9jbGFzc5RoDIwJcmV0cnlhYmxllE6MCGRvY3NfdXJslGgMdWgZfZRoG4+UKGgeaAdoCZBoHU51Yi4=", + "verify__status_completed_modified_at_crosses_midnight_by_minutes.json": "gASVCQoAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAljb21wbGV0ZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUaACMDFZlcmlmaWNhdGlvbpSTlCmBlH2UKGgFfZQojA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSMBWNsYWltlIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMCnZpc2liaWxpdHmUjAdwcml2YXRllIwFZGVwdGiUjAhzdGFuZGFyZJSMBmRvbWFpbpSMB1NjaWVuY2WUjAhlbnRpdGllc5RdlGgAjAlFbnRpdHlSZWaUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUVhcnRolIwDcWlklE51aBl9lGgbj5QoaDVoN5BoHU51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoGX2UaBuPlChoUGhYaFRoUmhWkGgdTnViaEwpgZR9lChoBX2UKGhQjANFU0GUaFKMEEVhcnRoIGZyb20gc3BhY2WUaFSMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaFaMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaFiMCjIwMjUtMDEtMTaUdWgZfZRoG4+UKGhQaFhoVGhSaFaQaB1OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoRV2UdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJocSmBlH2UKGgFfZQoaHWMClJldmlld2VyIEKUaHeMB1NvdXJjZXOUaHlHQCIAAAAAAABoeowXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaEVdlIwNd2VhayBzb3VyY2UgQZRhdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoGX2UaBuPlChokWiTaI+QaB1OdWKMCmRlYmF0ZV9jb26UaIspgZR9lChoBX2UKGiPjAdTa2VwdGljlGiRjCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGiTjCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBl9lGgbj5QoaJFok2iPkGgdTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgZfZRoG4+UKGhuaJdobGigaImQaB1OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDIzOjU1OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lIwgMjAyNi0xMC0wMlQwMDowMzowMC4xMjM0NTYrMDA6MDCUjAhsYW5ndWFnZZSMAmVulIwIY292ZXJhZ2WUaACMCENvdmVyYWdllJOUKYGUfZQoaAV9lChoB4wJdW5jb3ZlcmVklIwHcmVhc29uc5RdlIwEcGxhbpRhjA5jZXJ0aWZpY2F0ZV9pZJROjA9jZXJ0aWZpY2F0ZV91cmyUTowFYXNfb2aUTowIY3VycmVuY3mUjANFVVKUjANjYXCUTRAnjAlhZ2dyZWdhdGWUSiChBwCMDXRlcm1zX3ZlcnNpb26UjAJ2MZR1aBl9lGgbj5QoaLpotWi5aLZoB2i3aLtotGixkGgdTnVidWgZfZRoG4+UKGgkaC5oPmimaENoKGgsaEFoJmgqaKRoPGg6aEhoRWioaKpoSWhmaECQaB1OdWKMBmNsYWltc5RdlIwKY2FuZGlkYXRlc5RdlIwOc2ltaWxhcl9jbGFpbXOUXZSMBWVycm9ylGgMjA5mYWlsdXJlX3JlYXNvbpRoDIwOZmFpbHVyZV9kZXRhaWyUaAyMDWZhaWx1cmVfY2xhc3OUaAyMCXJldHJ5YWJsZZROjAhkb2NzX3VybJRoDHVoGX2UaBuPlChoHmgHaAmQaB1OdWIu", + "verify__status_completed_modified_at_same_day_hours_apart.json": "gASV5wkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAljb21wbGV0ZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUaACMDFZlcmlmaWNhdGlvbpSTlCmBlH2UKGgFfZQojA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSMBWNsYWltlIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMCnZpc2liaWxpdHmUjAdwcml2YXRllIwFZGVwdGiUjAhzdGFuZGFyZJSMBmRvbWFpbpSMB1NjaWVuY2WUjAhlbnRpdGllc5RdlGgAjAlFbnRpdHlSZWaUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUVhcnRolIwDcWlklE51aBl9lGgbj5QoaDVoN5BoHU51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoGX2UaBuPlChoUGhYaFRoUmhWkGgdTnViaEwpgZR9lChoBX2UKGhQjANFU0GUaFKMEEVhcnRoIGZyb20gc3BhY2WUaFSMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaFaMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaFiMCjIwMjUtMDEtMTaUdWgZfZRoG4+UKGhQaFhoVGhSaFaQaB1OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoRV2UdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJocSmBlH2UKGgFfZQoaHWMClJldmlld2VyIEKUaHeMB1NvdXJjZXOUaHlHQCIAAAAAAABoeowXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaEVdlIwNd2VhayBzb3VyY2UgQZRhdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoGX2UaBuPlChokWiTaI+QaB1OdWKMCmRlYmF0ZV9jb26UaIspgZR9lChoBX2UKGiPjAdTa2VwdGljlGiRjCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGiTjCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBl9lGgbj5QoaJFok2iPkGgdTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgZfZRoG4+UKGhuaJdobGigaImQaB1OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA4OjAwOjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKGgHjAl1bmNvdmVyZWSUjAdyZWFzb25zlF2UjARwbGFulGGMDmNlcnRpZmljYXRlX2lklE6MD2NlcnRpZmljYXRlX3VybJROjAVhc19vZpROjAhjdXJyZW5jeZSMA0VVUpSMA2NhcJRNECeMCWFnZ3JlZ2F0ZZRKIKEHAIwNdGVybXNfdmVyc2lvbpSMAnYxlHVoGX2UaBuPlChouWi0aLhotWgHaLZoumizaLCQaB1OdWJ1aBl9lGgbj5QoaCRoLmg+aKZoQ2goaCxoQWgmaCpopGg8aDpoSGhFaKdoqWhJaGZoQJBoHU51YowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUaAyMDmZhaWx1cmVfcmVhc29ulGgMjA5mYWlsdXJlX2RldGFpbJRoDIwNZmFpbHVyZV9jbGFzc5RoDIwJcmV0cnlhYmxllE6MCGRvY3NfdXJslGgMdWgZfZRoG4+UKGgeaAdoCZBoHU51Yi4=", + "verify__status_failed.json": "gASVbAIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAZmYWlsZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUjCNQaXBlbGluZSBzdG9wcGVkIGF0OiByZXNlYXJjaF9lbXB0eZSMDmZhaWx1cmVfcmVhc29ulIwOcmVzZWFyY2hfZW1wdHmUjA5mYWlsdXJlX2RldGFpbJRoDIwNZmFpbHVyZV9jbGFzc5SMFWluc3VmZmljaWVudF9ldmlkZW5jZZSMCXJldHJ5YWJsZZSJjAhkb2NzX3VybJSMMWh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyNpbnN1ZmZpY2llbnQtZXZpZGVuY2WUdWgZfZRoG4+UKGgJaAdoJ2gtaCpoLGglkGgdTnViLg==", + "verify__status_failed_after_a_while.json": "gASVVgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAZmYWlsZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUjCRQaXBlbGluZSBzdG9wcGVkOiBjb25jbHVzaW9uX2ZhaWxlZC6UjA5mYWlsdXJlX3JlYXNvbpSMEWNvbmNsdXNpb25fZmFpbGVklIwOZmFpbHVyZV9kZXRhaWyUaAyMDWZhaWx1cmVfY2xhc3OUjAhpbnRlcm5hbJSMCXJldHJ5YWJsZZSJjAhkb2NzX3VybJSMJGh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyNpbnRlcm5hbJR1aBl9lGgbj5QoaAloB2gnaC1oKmgsaCWQaB1OdWIu", + "verify__status_failed_after_a_while_framing.json": "gASVaAIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAZmYWlsZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUjCFQaXBlbGluZSBzdG9wcGVkOiBmcmFtaW5nX2ZhaWxlZC6UjA5mYWlsdXJlX3JlYXNvbpSMDmZyYW1pbmdfZmFpbGVklIwOZmFpbHVyZV9kZXRhaWyUaAyMDWZhaWx1cmVfY2xhc3OUjBR1cHN0cmVhbV91bmF2YWlsYWJsZZSMCXJldHJ5YWJsZZSIjAhkb2NzX3VybJSMMGh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyN1cHN0cmVhbS11bmF2YWlsYWJsZZR1aBl9lGgbj5QoaAloB2gnaC1oKmgsaCWQaB1OdWIu", + "verify__status_failed_retryable.json": "gASVdAIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAZmYWlsZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUjChQaXBlbGluZSBzdG9wcGVkIGF0OiBhZGp1ZGljYXRpb25fZmFpbGVklIwOZmFpbHVyZV9yZWFzb26UjBNhZGp1ZGljYXRpb25fZmFpbGVklIwOZmFpbHVyZV9kZXRhaWyUaAyMDWZhaWx1cmVfY2xhc3OUjBR1cHN0cmVhbV91bmF2YWlsYWJsZZSMCXJldHJ5YWJsZZSIjAhkb2NzX3VybJSMMGh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyN1cHN0cmVhbS11bmF2YWlsYWJsZZR1aBl9lGgbj5QoaAloB2gnaC1oKmgsaCWQaB1OdWIu", + "verify__status_needs_input.json": "gASVGAMAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAtuZWVkc19pbnB1dJSMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJSMBnJlYXNvbpSMC211bHRpX2NsYWltlIwEaGludJSMYFRoZSB0ZXh0IGhvbGRzIHNldmVyYWwgZGlzdGluY3QgY2xhaW1zLiBTZW5kIHRoZSBvbmVzIHRvIGNoZWNrIHRvIFBPU1QgL3ZlcmlmeS97dGFza19pZH0vc2VsZWN0LpSMCHByb2dyZXNzlGgAjAhQcm9ncmVzc5STlCmBlH2UKGgFfZQojARzdGVwlIwAlIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UKGgAjA5DYW5kaWRhdGVDbGFpbZSTlCmBlH2UKGgFfZQojAR0ZXh0lIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMBmRvbWFpbpSMB1NjaWVuY2WUdWgbfZRoHY+UKGgqaCiQaB9OdWJoJCmBlH2UKGgFfZQoaCiMIVdhdGVyIGJvaWxzIGF0IDEwMEMgYXQgc2VhIGxldmVsLpRoKowHU2NpZW5jZZR1aBt9lGgdj5QoaCpoKJBoH051YmWMCmNhbmRpZGF0ZXOUXZSMDnNpbWlsYXJfY2xhaW1zlF2UjAVlcnJvcpRoFowOZmFpbHVyZV9yZWFzb26UaBaMDmZhaWx1cmVfZGV0YWlslGgWjA1mYWlsdXJlX2NsYXNzlGgWjAlyZXRyeWFibGWUTowIZG9jc191cmyUaBZ1aBt9lGgdj5QoaA1oC2gJaAdoIZBoH051Yi4=", + "verify__status_not_a_claim.json": "gASV3wIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAZmYWlsZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lIyPVGhlIGlucHV0IGlzIGEgZ3JlZXRpbmcsIG5vdCBhIHN0YXRlbWVudCB0aGF0IGNhbiBiZSBjaGVja2VkLiBTZW5kIG9uZSBmYWN0dWFsIGNsYWltLCBvciBydW4gdGhlIHRleHQgdGhyb3VnaCAvZXh0cmFjdCB0byBlbnVtZXJhdGUgaXRzIGNsYWltcy6UjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUjBdOb3QgYSB2ZXJpZmlhYmxlIGNsYWltLpSMDmZhaWx1cmVfcmVhc29ulIwLbm90X2FfY2xhaW2UjA5mYWlsdXJlX2RldGFpbJRoDIwNZmFpbHVyZV9jbGFzc5SMDWludmFsaWRfaW5wdXSUjAlyZXRyeWFibGWUiYwIZG9jc191cmyUjClodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjaW52YWxpZC1pbnB1dJR1aBp9lGgcj5QoaA1oCWgHaChoLmgraC1oJpBoHk51Yi4=", + "verify__status_not_a_claim_after_a_while.json": "gASVVAIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAZmYWlsZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUjB5QaXBlbGluZSBzdG9wcGVkOiBub3RfYV9jbGFpbS6UjA5mYWlsdXJlX3JlYXNvbpSMC25vdF9hX2NsYWltlIwOZmFpbHVyZV9kZXRhaWyUaAyMDWZhaWx1cmVfY2xhc3OUjA1pbnZhbGlkX2lucHV0lIwJcmV0cnlhYmxllImMCGRvY3NfdXJslIwpaHR0cHM6Ly9sZW56LmlvL2RvY3MvZXJyb3JzI2ludmFsaWQtaW5wdXSUdWgZfZRoG4+UKGgJaAdoJ2gtaCpoLGglkGgdTnViLg==", + "verify__status_older_run_completed.json": "gASV5wkAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAljb21wbGV0ZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUaACMDFZlcmlmaWNhdGlvbpSTlCmBlH2UKGgFfZQojA92ZXJpZmljYXRpb25faWSUjAg2OGNhNGFhZpSMBWNsYWltlIwTVGhlIEVhcnRoIGlzIHJvdW5kLpSMCnZpc2liaWxpdHmUjAdwcml2YXRllIwFZGVwdGiUjAhzdGFuZGFyZJSMBmRvbWFpbpSMB1NjaWVuY2WUjAhlbnRpdGllc5RdlGgAjAlFbnRpdHlSZWaUk5QpgZR9lChoBX2UKIwEbmFtZZSMBUVhcnRolIwDcWlklE51aBl9lGgbj5QoaDVoN5BoHU51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoGX2UaBuPlChoUGhYaFRoUmhWkGgdTnViaEwpgZR9lChoBX2UKGhQjANFU0GUaFKMEEVhcnRoIGZyb20gc3BhY2WUaFSMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaFaMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaFiMCjIwMjUtMDEtMTaUdWgZfZRoG4+UKGhQaFhoVGhSaFaQaB1OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoRV2UdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJocSmBlH2UKGgFfZQoaHWMClJldmlld2VyIEKUaHeMB1NvdXJjZXOUaHlHQCIAAAAAAABoeowXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaEVdlIwNd2VhayBzb3VyY2UgQZRhdWgZfZRoG4+UKGhFaHdodWh5aHqQaB1OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoGX2UaBuPlChokWiTaI+QaB1OdWKMCmRlYmF0ZV9jb26UaIspgZR9lChoBX2UKGiPjAdTa2VwdGljlGiRjCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGiTjCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBl9lGgbj5QoaJFok2iPkGgdTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgZfZRoG4+UKGhuaJdobGigaImQaB1OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKGgHjAl1bmNvdmVyZWSUjAdyZWFzb25zlF2UjARwbGFulGGMDmNlcnRpZmljYXRlX2lklE6MD2NlcnRpZmljYXRlX3VybJROjAVhc19vZpROjAhjdXJyZW5jeZSMA0VVUpSMA2NhcJRNECeMCWFnZ3JlZ2F0ZZRKIKEHAIwNdGVybXNfdmVyc2lvbpSMAnYxlHVoGX2UaBuPlChouWi0aLhotWgHaLZoumizaLCQaB1OdWJ1aBl9lGgbj5QoaCRoLmg+aKZoQ2goaCxoQWgmaCpopGg8aDpoSGhFaKdoqWhJaGZoQJBoHU51YowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUaAyMDmZhaWx1cmVfcmVhc29ulGgMjA5mYWlsdXJlX2RldGFpbJRoDIwNZmFpbHVyZV9jbGFzc5RoDIwJcmV0cnlhYmxllE6MCGRvY3NfdXJslGgMdWgZfZRoG4+UKGgeaAdoCZBoHU51Yi4=", + "verify__status_older_run_failed_crashed.json": "gASVOwIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAZmYWlsZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUjBBQaXBlbGluZSBmYWlsZWQulIwOZmFpbHVyZV9yZWFzb26UjAp0YXNrX2Vycm9ylIwOZmFpbHVyZV9kZXRhaWyUaAyMDWZhaWx1cmVfY2xhc3OUjAhpbnRlcm5hbJSMCXJldHJ5YWJsZZSJjAhkb2NzX3VybJSMJGh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyNpbnRlcm5hbJR1aBl9lGgbj5QoaAloB2gnaC1oKmgsaCWQaB1OdWIu", + "verify__status_older_run_failed_insufficient_evidence.json": "gASVbAIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAZmYWlsZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUjCNQaXBlbGluZSBzdG9wcGVkIGF0OiByZXNlYXJjaF9lbXB0eZSMDmZhaWx1cmVfcmVhc29ulIwOcmVzZWFyY2hfZW1wdHmUjA5mYWlsdXJlX2RldGFpbJRoDIwNZmFpbHVyZV9jbGFzc5SMFWluc3VmZmljaWVudF9ldmlkZW5jZZSMCXJldHJ5YWJsZZSJjAhkb2NzX3VybJSMMWh0dHBzOi8vbGVuei5pby9kb2NzL2Vycm9ycyNpbnN1ZmZpY2llbnQtZXZpZGVuY2WUdWgZfZRoG4+UKGgJaAdoJ2gtaCpoLGglkGgdTnViLg==", + "verify__status_older_run_in_progress.json": "gASVBgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjApwcm9jZXNzaW5nlIwHdGFza19pZJSMIDdjZmYxOGRhMmQ5NzlkNjM3MGU1NGExNjBiZTEyMWFklIwGcmVhc29ulIwAlIwEaGludJRoDIwIcHJvZ3Jlc3OUaACMCFByb2dyZXNzlJOUKYGUfZQoaAV9lCiMBHN0ZXCUjAhyZXNlYXJjaJSMBWluZGV4lEsCjAV0b3RhbJRLBYwPZWxhcHNlZF9zZWNvbmRzlEsBjBJwb2xsX2FmdGVyX3NlY29uZHOUSwV1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgYaBdoFmgUaBmQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMBnJlc3VsdJROjAZjbGFpbXOUXZSMCmNhbmRpZGF0ZXOUXZSMDnNpbWlsYXJfY2xhaW1zlF2UjAVlcnJvcpRoDIwOZmFpbHVyZV9yZWFzb26UaAyMDmZhaWx1cmVfZGV0YWlslGgMjA1mYWlsdXJlX2NsYXNzlGgMjAlyZXRyeWFibGWUTowIZG9jc191cmyUaAx1aBp9lGgcj5QoaA5oB2gJkGgeTnViLg==", + "verify__status_processing.json": "gASVBgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjApwcm9jZXNzaW5nlIwHdGFza19pZJSMIDdjZmYxOGRhMmQ5NzlkNjM3MGU1NGExNjBiZTEyMWFklIwGcmVhc29ulIwAlIwEaGludJRoDIwIcHJvZ3Jlc3OUaACMCFByb2dyZXNzlJOUKYGUfZQoaAV9lCiMBHN0ZXCUjAhyZXNlYXJjaJSMBWluZGV4lEsCjAV0b3RhbJRLBYwPZWxhcHNlZF9zZWNvbmRzlEsBjBJwb2xsX2FmdGVyX3NlY29uZHOUSwV1jBJfX3B5ZGFudGljX2V4dHJhX1+UfZSMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgYaBdoFmgUaBmQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMBnJlc3VsdJROjAZjbGFpbXOUXZSMCmNhbmRpZGF0ZXOUXZSMDnNpbWlsYXJfY2xhaW1zlF2UjAVlcnJvcpRoDIwOZmFpbHVyZV9yZWFzb26UaAyMDmZhaWx1cmVfZGV0YWlslGgMjA1mYWlsdXJlX2NsYXNzlGgMjAlyZXRyeWFibGWUTowIZG9jc191cmyUaAx1aBp9lGgcj5QoaA5oB2gJkGgeTnViLg==", + "verify__status_processing_after_a_while.json": "gASVCgIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjApwcm9jZXNzaW5nlIwHdGFza19pZJSMIDdjZmYxOGRhMmQ5NzlkNjM3MGU1NGExNjBiZTEyMWFklIwGcmVhc29ulIwAlIwEaGludJRoDIwIcHJvZ3Jlc3OUaACMCFByb2dyZXNzlJOUKYGUfZQoaAV9lCiMBHN0ZXCUjAxhZGp1ZGljYXRpb26UjAVpbmRleJRLBIwFdG90YWyUSwWMD2VsYXBzZWRfc2Vjb25kc5RLAYwScG9sbF9hZnRlcl9zZWNvbmRzlEsFdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGGgXaBZoFGgZkIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUaAyMDmZhaWx1cmVfcmVhc29ulGgMjA5mYWlsdXJlX2RldGFpbJRoDIwNZmFpbHVyZV9jbGFzc5RoDIwJcmV0cnlhYmxllE6MCGRvY3NfdXJslGgMdWgafZRoHI+UKGgOaAdoCZBoHk51Yi4=", + "verify__status_task_stuck.json": "gASVewIAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwKVGFza1N0YXR1c5STlCmBlH2UKIwIX19kaWN0X1+UfZQojAZzdGF0dXOUjAZmYWlsZWSUjAd0YXNrX2lklIwgN2NmZjE4ZGEyZDk3OWQ2MzcwZTU0YTE2MGJlMTIxYWSUjAZyZWFzb26UjACUjARoaW50lGgMjAhwcm9ncmVzc5RoAIwIUHJvZ3Jlc3OUk5QpgZR9lChoBX2UKIwEc3RlcJRoDIwFaW5kZXiUTowFdG90YWyUTowPZWxhcHNlZF9zZWNvbmRzlE6MEnBvbGxfYWZ0ZXJfc2Vjb25kc5ROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlIwUX19weWRhbnRpY19wcml2YXRlX1+UTnVijAZyZXN1bHSUTowGY2xhaW1zlF2UjApjYW5kaWRhdGVzlF2UjA5zaW1pbGFyX2NsYWltc5RdlIwFZXJyb3KUjDhUaGUgdGFzayB3YXMgbmV2ZXIgY29tcGxldGVkIGFuZCBoYXMgYmVlbiBtYXJrZWQgZmFpbGVkLpSMDmZhaWx1cmVfcmVhc29ulIwKdGFza19zdHVja5SMDmZhaWx1cmVfZGV0YWlslGgMjA1mYWlsdXJlX2NsYXNzlIwUdXBzdHJlYW1fdW5hdmFpbGFibGWUjAlyZXRyeWFibGWUiIwIZG9jc191cmyUjDBodHRwczovL2xlbnouaW8vZG9jcy9lcnJvcnMjdXBzdHJlYW0tdW5hdmFpbGFibGWUdWgZfZRoG4+UKGgJaAdoJ2gtaCpoLGglkGgdTnViLg==", + "verify__submit_202.json": "gASV/AAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVGFza0FjY2VwdGVklJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJSMCmNsYWltX3RleHSUjACUdYwSX19weWRhbnRpY19leHRyYV9flH2UKIwGc3RhdHVzlIwGcXVldWVklIwIY2hhaW5faWSUjBA5OWEwYTljYTg5ZTFlNzJjlHWMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgPaA1oB5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51Yi4=", + "verify__submit_202_options.json": "gASV/AAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVGFza0FjY2VwdGVklJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJSMCmNsYWltX3RleHSUjACUdYwSX19weWRhbnRpY19leHRyYV9flH2UKIwGc3RhdHVzlIwGcXVldWVklIwIY2hhaW5faWSUjBA5OWEwYTljYTg5ZTFlNzJjlHWMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgPaA1oB5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51Yi4=", + "verify__submit_202_text_alias.json": "gASV/AAAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVGFza0FjY2VwdGVklJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMB3Rhc2tfaWSUjCA3Y2ZmMThkYTJkOTc5ZDYzNzBlNTRhMTYwYmUxMjFhZJSMCmNsYWltX3RleHSUjACUdYwSX19weWRhbnRpY19leHRyYV9flH2UKIwGc3RhdHVzlIwGcXVldWVklIwIY2hhaW5faWSUjBA5OWEwYTljYTg5ZTFlNzJjlHWMF19fcHlkYW50aWNfZmllbGRzX3NldF9flI+UKGgPaA1oB5CMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51Yi4=", + "verify__verification_200.json": "gASVXAgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UaACMCUVudGl0eVJlZpSTlCmBlH2UKGgFfZQojARuYW1llIwFRWFydGiUjANxaWSUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBhoGpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoG32UaB2PlChoNmg+aDpoOGg8kGgfTnViaDIpgZR9lChoBX2UKGg2jANFU0GUaDiMEEVhcnRoIGZyb20gc3BhY2WUaDqMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaDyMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaD6MCjIwMjUtMDEtMTaUdWgbfZRoHY+UKGg2aD5oOmg4aDyQaB9OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoK12UdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJoVymBlH2UKGgFfZQoaFuMClJldmlld2VyIEKUaF2MB1NvdXJjZXOUaF9HQCIAAAAAAABoYIwXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaCtdlIwNd2VhayBzb3VyY2UgQZRhdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoG32UaB2PlChod2h5aHWQaB9OdWKMCmRlYmF0ZV9jb26UaHEpgZR9lChoBX2UKGh1jAdTa2VwdGljlGh3jCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGh5jCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBt9lGgdj5QoaHdoeWh1kGgfTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgbfZRoHY+UKGhUaH1oUmiGaG+QaB9OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKIwGc3RhdHVzlIwJdW5jb3ZlcmVklIwHcmVhc29uc5RdlIwEcGxhbpRhjA5jZXJ0aWZpY2F0ZV9pZJROjA9jZXJ0aWZpY2F0ZV91cmyUTowFYXNfb2aUTowIY3VycmVuY3mUjANFVVKUjANjYXCUTRAnjAlhZ2dyZWdhdGWUSiChBwCMDXRlcm1zX3ZlcnNpb26UjAJ2MZR1aBt9lGgdj5QoaKBom2ifaJxolWidaKFommiXkGgfTnVidWgbfZRoHY+UKGgHaBFoJGiMaCloC2gPaCdoCWgNaIpoImggaC5oK2iNaI9oL2hMaCaQaB9OdWIu", + "verify__verification_200_covered.json": "gASVzQgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UaACMCUVudGl0eVJlZpSTlCmBlH2UKGgFfZQojARuYW1llIwFRWFydGiUjANxaWSUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBhoGpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoG32UaB2PlChoNmg+aDpoOGg8kGgfTnViaDIpgZR9lChoBX2UKGg2jANFU0GUaDiMEEVhcnRoIGZyb20gc3BhY2WUaDqMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaDyMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaD6MCjIwMjUtMDEtMTaUdWgbfZRoHY+UKGg2aD5oOmg4aDyQaB9OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoK12UdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJoVymBlH2UKGgFfZQoaFuMClJldmlld2VyIEKUaF2MB1NvdXJjZXOUaF9HQCIAAAAAAABoYIwXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaCtdlIwNd2VhayBzb3VyY2UgQZRhdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoG32UaB2PlChod2h5aHWQaB9OdWKMCmRlYmF0ZV9jb26UaHEpgZR9lChoBX2UKGh1jAdTa2VwdGljlGh3jCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGh5jCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBt9lGgdj5QoaHdoeWh1kGgfTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgbfZRoHY+UKGhUaH1oUmiGaG+QaB9OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKIwGc3RhdHVzlIwHY292ZXJlZJSMB3JlYXNvbnOUXZSMDmNlcnRpZmljYXRlX2lklIwgOTViMGYzZGQwMDhiNDY4NDZiNmRkNmIxNTA5OWUyYjOUjA9jZXJ0aWZpY2F0ZV91cmyUjDxodHRwczovL2xlbnouaW8vY2VydGlmaWNhdGUvOTViMGYzZGQwMDhiNDY4NDZiNmRkNmIxNTA5OWUyYjOUjAVhc19vZpSMGTIwMjYtMDMtMTBUMTI6MDE6MzArMDA6MDCUjAhjdXJyZW5jeZSMA0VVUpSMA2NhcJRNECeMCWFnZ3JlZ2F0ZZRKIKEHAIwNdGVybXNfdmVyc2lvbpSMAnYxlHVoG32UaB2PlChoomibaKFonWiVaJ9oo2iZaJeQaB9OdWJ1aBt9lGgdj5QoaAdoEWgkaIxoKWgLaA9oJ2gJaA1oimgiaCBoLmgraI1oj2gvaExoJpBoH051Yi4=", + "verify__verification_200_modified_at_crosses_midnight_by_minutes.json": "gASVfggAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UaACMCUVudGl0eVJlZpSTlCmBlH2UKGgFfZQojARuYW1llIwFRWFydGiUjANxaWSUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBhoGpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoG32UaB2PlChoNmg+aDpoOGg8kGgfTnViaDIpgZR9lChoBX2UKGg2jANFU0GUaDiMEEVhcnRoIGZyb20gc3BhY2WUaDqMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaDyMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaD6MCjIwMjUtMDEtMTaUdWgbfZRoHY+UKGg2aD5oOmg4aDyQaB9OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoK12UdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJoVymBlH2UKGgFfZQoaFuMClJldmlld2VyIEKUaF2MB1NvdXJjZXOUaF9HQCIAAAAAAABoYIwXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaCtdlIwNd2VhayBzb3VyY2UgQZRhdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoG32UaB2PlChod2h5aHWQaB9OdWKMCmRlYmF0ZV9jb26UaHEpgZR9lChoBX2UKGh1jAdTa2VwdGljlGh3jCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGh5jCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBt9lGgdj5QoaHdoeWh1kGgfTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgbfZRoHY+UKGhUaH1oUmiGaG+QaB9OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDIzOjU1OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lIwgMjAyNi0xMC0wMlQwMDowMzowMC4xMjM0NTYrMDA6MDCUjAhsYW5ndWFnZZSMAmVulIwIY292ZXJhZ2WUaACMCENvdmVyYWdllJOUKYGUfZQoaAV9lCiMBnN0YXR1c5SMCXVuY292ZXJlZJSMB3JlYXNvbnOUXZSMBHBsYW6UYYwOY2VydGlmaWNhdGVfaWSUTowPY2VydGlmaWNhdGVfdXJslE6MBWFzX29mlE6MCGN1cnJlbmN5lIwDRVVSlIwDY2FwlE0QJ4wJYWdncmVnYXRllEogoQcAjA10ZXJtc192ZXJzaW9ulIwCdjGUdWgbfZRoHY+UKGihaJxooGidaJZonmiiaJtomJBoH051YnVoG32UaB2PlChoB2gRaCRojGgpaAtoD2gnaAloDWiKaCJoIGguaCtojmiQaC9oTGgmkGgfTnViLg==", + "verify__verification_200_modified_at_null.json": "gASVXAgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UaACMCUVudGl0eVJlZpSTlCmBlH2UKGgFfZQojARuYW1llIwFRWFydGiUjANxaWSUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBhoGpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoG32UaB2PlChoNmg+aDpoOGg8kGgfTnViaDIpgZR9lChoBX2UKGg2jANFU0GUaDiMEEVhcnRoIGZyb20gc3BhY2WUaDqMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaDyMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaD6MCjIwMjUtMDEtMTaUdWgbfZRoHY+UKGg2aD5oOmg4aDyQaB9OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoK12UdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJoVymBlH2UKGgFfZQoaFuMClJldmlld2VyIEKUaF2MB1NvdXJjZXOUaF9HQCIAAAAAAABoYIwXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaCtdlIwNd2VhayBzb3VyY2UgQZRhdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoG32UaB2PlChod2h5aHWQaB9OdWKMCmRlYmF0ZV9jb26UaHEpgZR9lChoBX2UKGh1jAdTa2VwdGljlGh3jCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGh5jCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBt9lGgdj5QoaHdoeWh1kGgfTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgbfZRoHY+UKGhUaH1oUmiGaG+QaB9OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKIwGc3RhdHVzlIwJdW5jb3ZlcmVklIwHcmVhc29uc5RdlIwEcGxhbpRhjA5jZXJ0aWZpY2F0ZV9pZJROjA9jZXJ0aWZpY2F0ZV91cmyUTowFYXNfb2aUTowIY3VycmVuY3mUjANFVVKUjANjYXCUTRAnjAlhZ2dyZWdhdGWUSiChBwCMDXRlcm1zX3ZlcnNpb26UjAJ2MZR1aBt9lGgdj5QoaKBom2ifaJxolWidaKFommiXkGgfTnVidWgbfZRoHY+UKGgHaBFoJGiMaCloC2gPaCdoCWgNaIpoImggaC5oK2iNaI9oL2hMaCaQaB9OdWIu", + "verify__verification_200_modified_at_same_day_hours_apart.json": "gASVXAgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UaACMCUVudGl0eVJlZpSTlCmBlH2UKGgFfZQojARuYW1llIwFRWFydGiUjANxaWSUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBhoGpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoG32UaB2PlChoNmg+aDpoOGg8kGgfTnViaDIpgZR9lChoBX2UKGg2jANFU0GUaDiMEEVhcnRoIGZyb20gc3BhY2WUaDqMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaDyMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaD6MCjIwMjUtMDEtMTaUdWgbfZRoHY+UKGg2aD5oOmg4aDyQaB9OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoK12UdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJoVymBlH2UKGgFfZQoaFuMClJldmlld2VyIEKUaF2MB1NvdXJjZXOUaF9HQCIAAAAAAABoYIwXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaCtdlIwNd2VhayBzb3VyY2UgQZRhdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoG32UaB2PlChod2h5aHWQaB9OdWKMCmRlYmF0ZV9jb26UaHEpgZR9lChoBX2UKGh1jAdTa2VwdGljlGh3jCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGh5jCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBt9lGgdj5QoaHdoeWh1kGgfTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgbfZRoHY+UKGhUaH1oUmiGaG+QaB9OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA4OjAwOjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKIwGc3RhdHVzlIwJdW5jb3ZlcmVklIwHcmVhc29uc5RdlIwEcGxhbpRhjA5jZXJ0aWZpY2F0ZV9pZJROjA9jZXJ0aWZpY2F0ZV91cmyUTowFYXNfb2aUTowIY3VycmVuY3mUjANFVVKUjANjYXCUTRAnjAlhZ2dyZWdhdGWUSiChBwCMDXRlcm1zX3ZlcnNpb26UjAJ2MZR1aBt9lGgdj5QoaKBom2ifaJxolWidaKFommiXkGgfTnVidWgbfZRoHY+UKGgHaBFoJGiMaCloC2gPaCdoCWgNaIpoImggaC5oK2iNaI9oL2hMaCaQaB9OdWIu", + "verify__verification_200_modified_at_set.json": "gASVfggAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UaACMCUVudGl0eVJlZpSTlCmBlH2UKGgFfZQojARuYW1llIwFRWFydGiUjANxaWSUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBhoGpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoG32UaB2PlChoNmg+aDpoOGg8kGgfTnViaDIpgZR9lChoBX2UKGg2jANFU0GUaDiMEEVhcnRoIGZyb20gc3BhY2WUaDqMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaDyMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaD6MCjIwMjUtMDEtMTaUdWgbfZRoHY+UKGg2aD5oOmg4aDyQaB9OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoK12UdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJoVymBlH2UKGgFfZQoaFuMClJldmlld2VyIEKUaF2MB1NvdXJjZXOUaF9HQCIAAAAAAABoYIwXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaCtdlIwNd2VhayBzb3VyY2UgQZRhdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoG32UaB2PlChod2h5aHWQaB9OdWKMCmRlYmF0ZV9jb26UaHEpgZR9lChoBX2UKGh1jAdTa2VwdGljlGh3jCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGh5jCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBt9lGgdj5QoaHdoeWh1kGgfTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgbfZRoHY+UKGhUaH1oUmiGaG+QaB9OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDIzOjU1OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lIwgMjAyNi0xMC0wMlQwMDowMzowMC4xMjM0NTYrMDA6MDCUjAhsYW5ndWFnZZSMAmVulIwIY292ZXJhZ2WUaACMCENvdmVyYWdllJOUKYGUfZQoaAV9lCiMBnN0YXR1c5SMCXVuY292ZXJlZJSMB3JlYXNvbnOUXZSMBHBsYW6UYYwOY2VydGlmaWNhdGVfaWSUTowPY2VydGlmaWNhdGVfdXJslE6MBWFzX29mlE6MCGN1cnJlbmN5lIwDRVVSlIwDY2FwlE0QJ4wJYWdncmVnYXRllEogoQcAjA10ZXJtc192ZXJzaW9ulIwCdjGUdWgbfZRoHY+UKGihaJxooGidaJZonmiiaJtomJBoH051YnVoG32UaB2PlChoB2gRaCRojGgpaAtoD2gnaAloDWiKaCJoIGguaCtojmiQaC9oTGgmkGgfTnViLg==", + "verify__verification_200_result_json_conclusion_only.json": "gASVXgQAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UjA9wcmVzdW1lZF9pbnRlbnSUjACUjAd2ZXJkaWN0lIwEVHJ1ZZSMCmNvbmZpZGVuY2WUjARoaWdolIwKbGVuel9zY29yZZRLCYwLa2V5X2ZpbmRpbmeUjC5UaGUgRWFydGggaXMgYXBwcm94aW1hdGVseSBzcGhlcmljYWwgaW4gc2hhcGUulIwRZXhlY3V0aXZlX3N1bW1hcnmUjBZUaGUgY2xhaW0gaXMgdmVyaWZpZWQulIwId2FybmluZ3OUXZSMEXN1Z2dlc3RlZF9yZXdyaXRllE6MB3NvdXJjZXOUXZSMBWF1ZGl0lGgAjAVBdWRpdJSTlCmBlH2UKGgFfZQojBRhZGp1ZGljYXRpb25fc3VtbWFyeZRoFIwLYXNzZXNzbWVudHOUXZSMCmRlYmF0ZV9wcm+UaACMCkRlYmF0ZVNpZGWUk5QpgZR9lChoBX2UKIwEcm9sZZRoFIwIYXJndW1lbnSUaBSMCHJlYnV0dGFslGgUdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoM2g0aDKQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMCmRlYmF0ZV9jb26UaC4pgZR9lChoBX2UKGgyaBRoM2gUaDRoFHVoNX2UaDePlChoM2g0aDKQaDlOdWKMD3BhbmVsX2FncmVlbWVudJSMBXNwbGl0lHVoNX2UaDePlChoKmg6aCloQGgskGg5TnVijApjcmVhdGVkX2F0lIwgMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTYrMDA6MDCUjAttb2RpZmllZF9hdJROjAhsYW5ndWFnZZSMAmVulIwIY292ZXJhZ2WUaACMCENvdmVyYWdllJOUKYGUfZQoaAV9lCiMBnN0YXR1c5SMCXVuY292ZXJlZJSMB3JlYXNvbnOUXZSMBHBsYW6UYYwOY2VydGlmaWNhdGVfaWSUTowPY2VydGlmaWNhdGVfdXJslE6MBWFzX29mlE6MCGN1cnJlbmN5lIwDRVVSlIwDY2FwlE0QJ4wJYWdncmVnYXRllEogoQcAjA10ZXJtc192ZXJzaW9ulIwCdjGUdWg1fZRoN4+UKGhaaFVoWWhWaE9oV2hbaFRoUZBoOU51YnVoNX2UaDePlChoB2gRaBdoRmgcaAtoD2gaaAloDWhEaBVoE2ggaB5oR2hJaCFoI2gZkGg5TnViLg==", + "verify__verification_200_result_json_empty.json": "gASVXgQAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UjA9wcmVzdW1lZF9pbnRlbnSUjACUjAd2ZXJkaWN0lIwEVHJ1ZZSMCmNvbmZpZGVuY2WUjARoaWdolIwKbGVuel9zY29yZZRLCYwLa2V5X2ZpbmRpbmeUjC5UaGUgRWFydGggaXMgYXBwcm94aW1hdGVseSBzcGhlcmljYWwgaW4gc2hhcGUulIwRZXhlY3V0aXZlX3N1bW1hcnmUjBZUaGUgY2xhaW0gaXMgdmVyaWZpZWQulIwId2FybmluZ3OUXZSMEXN1Z2dlc3RlZF9yZXdyaXRllE6MB3NvdXJjZXOUXZSMBWF1ZGl0lGgAjAVBdWRpdJSTlCmBlH2UKGgFfZQojBRhZGp1ZGljYXRpb25fc3VtbWFyeZRoFIwLYXNzZXNzbWVudHOUXZSMCmRlYmF0ZV9wcm+UaACMCkRlYmF0ZVNpZGWUk5QpgZR9lChoBX2UKIwEcm9sZZRoFIwIYXJndW1lbnSUaBSMCHJlYnV0dGFslGgUdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoM2g0aDKQjBRfX3B5ZGFudGljX3ByaXZhdGVfX5ROdWKMCmRlYmF0ZV9jb26UaC4pgZR9lChoBX2UKGgyaBRoM2gUaDRoFHVoNX2UaDePlChoM2g0aDKQaDlOdWKMD3BhbmVsX2FncmVlbWVudJSMBXNwbGl0lHVoNX2UaDePlChoKmg6aCloQGgskGg5TnVijApjcmVhdGVkX2F0lIwgMjAyNi0xMC0wMVQwOTowNzowMC4xMjM0NTYrMDA6MDCUjAttb2RpZmllZF9hdJROjAhsYW5ndWFnZZSMAmVulIwIY292ZXJhZ2WUaACMCENvdmVyYWdllJOUKYGUfZQoaAV9lCiMBnN0YXR1c5SMCXVuY292ZXJlZJSMB3JlYXNvbnOUXZSMBHBsYW6UYYwOY2VydGlmaWNhdGVfaWSUTowPY2VydGlmaWNhdGVfdXJslE6MBWFzX29mlE6MCGN1cnJlbmN5lIwDRVVSlIwDY2FwlE0QJ4wJYWdncmVnYXRllEogoQcAjA10ZXJtc192ZXJzaW9ulIwCdjGUdWg1fZRoN4+UKGhaaFVoWWhWaE9oV2hbaFRoUZBoOU51YnVoNX2UaDePlChoB2gRaBdoRmgcaAtoD2gaaAloDWhEaBVoE2ggaB5oR2hJaCFoI2gZkGg5TnViLg==", + "verify__verification_200_result_json_old_shape_strings.json": "gASVZQUAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UjA9wcmVzdW1lZF9pbnRlbnSUjACUjAd2ZXJkaWN0lIwEVHJ1ZZSMCmNvbmZpZGVuY2WUjARoaWdolIwKbGVuel9zY29yZZRLCYwLa2V5X2ZpbmRpbmeUjC5UaGUgRWFydGggaXMgYXBwcm94aW1hdGVseSBzcGhlcmljYWwgaW4gc2hhcGUulIwRZXhlY3V0aXZlX3N1bW1hcnmUjBZUaGUgY2xhaW0gaXMgdmVyaWZpZWQulIwId2FybmluZ3OUXZSMEXN1Z2dlc3RlZF9yZXdyaXRllE6MB3NvdXJjZXOUXZRoAIwGU291cmNllJOUKYGUfZQoaAV9lCiMC3NvdXJjZV9uYW1llGgUjAV0aXRsZZRoFIwDdXJslIwVaHR0cHM6Ly9vbGQuZXhhbXBsZS9hlIwHc25pcHBldJSMCE9sZCByb3culIwEZGF0ZZRoFHWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaChoLmgqaCloLJCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMBWF1ZGl0lGgAjAVBdWRpdJSTlCmBlH2UKGgFfZQojBRhZGp1ZGljYXRpb25fc3VtbWFyeZRoFIwLYXNzZXNzbWVudHOUXZRoAIwKQXNzZXNzbWVudJSTlCmBlH2UKGgFfZQojA1wYW5lbGlzdF9uYW1llIwKUmV2aWV3ZXIgQZSMCmZvY3VzX2FyZWGUaBSMBXNjb3JllE6MCXJlYXNvbmluZ5RoFGgeXZR1aC99lGgxj5QoaB5oRGhCaEVoRpBoM051YmGMCmRlYmF0ZV9wcm+UaACMCkRlYmF0ZVNpZGWUk5QpgZR9lChoBX2UKIwEcm9sZZRoFIwIYXJndW1lbnSUaBSMCHJlYnV0dGFslGgUdWgvfZRoMY+UKGhRaFJoUJBoM051YowKZGViYXRlX2NvbpRoTCmBlH2UKGgFfZQoaFBoFGhRaBRoUmgUdWgvfZRoMY+UKGhRaFJoUJBoM051YowPcGFuZWxfYWdyZWVtZW50lIwFc3BsaXSUdWgvfZRoMY+UKGg7aFVoOmhbaEqQaDNOdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKIwGc3RhdHVzlIwJdW5jb3ZlcmVklIwHcmVhc29uc5RdlIwEcGxhbpRhjA5jZXJ0aWZpY2F0ZV9pZJROjA9jZXJ0aWZpY2F0ZV91cmyUTowFYXNfb2aUTowIY3VycmVuY3mUjANFVVKUjANjYXCUTRAnjAlhZ2dyZWdhdGWUSiChBwCMDXRlcm1zX3ZlcnNpb26UjAJ2MZR1aC99lGgxj5QoaHVocGh0aHFoamhyaHZob2hskGgzTnVidWgvfZRoMY+UKGgHaBFoF2hhaBxoC2gPaBpoCWgNaF9oFWgTaCBoHmhiaGRoIWg0aBmQaDNOdWIu", + "verify__verification_by_task_id_200.json": "gASVXAgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UaACMCUVudGl0eVJlZpSTlCmBlH2UKGgFfZQojARuYW1llIwFRWFydGiUjANxaWSUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBhoGpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMLlRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbCBpbiBzaGFwZS6UjBFleGVjdXRpdmVfc3VtbWFyeZSMFlRoZSBjbGFpbSBpcyB2ZXJpZmllZC6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoG32UaB2PlChoNmg+aDpoOGg8kGgfTnViaDIpgZR9lChoBX2UKGg2jANFU0GUaDiMEEVhcnRoIGZyb20gc3BhY2WUaDqMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaDyMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaD6MCjIwMjUtMDEtMTaUdWgbfZRoHY+UKGg2aD5oOmg4aDyQaB9OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoK12UdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJoVymBlH2UKGgFfZQoaFuMClJldmlld2VyIEKUaF2MB1NvdXJjZXOUaF9HQCIAAAAAAABoYIwXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaCtdlIwNd2VhayBzb3VyY2UgQZRhdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoG32UaB2PlChod2h5aHWQaB9OdWKMCmRlYmF0ZV9jb26UaHEpgZR9lChoBX2UKGh1jAdTa2VwdGljlGh3jCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGh5jCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBt9lGgdj5QoaHdoeWh1kGgfTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgbfZRoHY+UKGhUaH1oUmiGaG+QaB9OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKIwGc3RhdHVzlIwJdW5jb3ZlcmVklIwHcmVhc29uc5RdlIwEcGxhbpRhjA5jZXJ0aWZpY2F0ZV9pZJROjA9jZXJ0aWZpY2F0ZV91cmyUTowFYXNfb2aUTowIY3VycmVuY3mUjANFVVKUjANjYXCUTRAnjAlhZ2dyZWdhdGWUSiChBwCMDXRlcm1zX3ZlcnNpb26UjAJ2MZR1aBt9lGgdj5QoaKBom2ifaJxolWidaKFommiXkGgfTnVidWgbfZRoHY+UKGgHaBFoJGiMaCloC2gPaCdoCWgNaIpoImggaC5oK2iNaI9oL2hMaCaQaB9OdWIu", + "verify__verification_public_anonymous.json": "gASViQcAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMBnB1YmxpY5SMBWRlcHRolIwIc3RhbmRhcmSUjAZkb21haW6UjAdTY2llbmNllIwIZW50aXRpZXOUXZRoAIwJRW50aXR5UmVmlJOUKYGUfZQoaAV9lCiMBG5hbWWUjAVFYXJ0aJSMA3FpZJROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGGgakIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViYYwPcHJlc3VtZWRfaW50ZW50lIweVmVyaWZ5IGEgYmFzaWMgc2NpZW50aWZpYyBmYWN0lIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwEaGlnaJSMCmxlbnpfc2NvcmWUSwmMC2tleV9maW5kaW5nlIwuVGhlIEVhcnRoIGlzIGFwcHJveGltYXRlbHkgc3BoZXJpY2FsIGluIHNoYXBlLpSMEWV4ZWN1dGl2ZV9zdW1tYXJ5lIwWVGhlIGNsYWltIGlzIHZlcmlmaWVkLpSMCHdhcm5pbmdzlF2UjBlSZWxpZXMgb24gbGltaXRlZCBzb3VyY2VzlGGMEXN1Z2dlc3RlZF9yZXdyaXRllE6MB3NvdXJjZXOUXZQoaACMBlNvdXJjZZSTlCmBlH2UKGgFfZQojAtzb3VyY2VfbmFtZZSMBE5BU0GUjAV0aXRsZZSMFlRoZSBzaGFwZSBvZiB0aGUgRWFydGiUjAN1cmyUjBpodHRwczovL25hc2EuZXhhbXBsZS9zaGFwZZSMB3NuaXBwZXSUjCtTYXRlbGxpdGUgaW1hZ2VyeSBzaG93cyBhbiBvYmxhdGUgc3BoZXJvaWQulIwEZGF0ZZSMCjIwMjUtMDEtMTWUdWgbfZRoHY+UKGg2aD5oOmg4aDyQaB9OdWJoMimBlH2UKGgFfZQoaDaMA0VTQZRoOIwQRWFydGggZnJvbSBzcGFjZZRoOowZaHR0cHM6Ly9lc2EuZXhhbXBsZS9lYXJ0aJRoPIwrT3JiaXRhbCBtZWFzdXJlbWVudHMgY29uZmlybSB0aGUgY3VydmF0dXJlLpRoPowKMjAyNS0wMS0xNpR1aBt9lGgdj5QoaDZoPmg6aDhoPJBoH051YmWMBWF1ZGl0lGgAjAVBdWRpdJSTlCmBlH2UKGgFfZQojBRhZGp1ZGljYXRpb25fc3VtbWFyeZSMFkJvdGggcmV2aWV3ZXJzIGFncmVlZC6UjAthc3Nlc3NtZW50c5RdlChoAIwKQXNzZXNzbWVudJSTlCmBlH2UKGgFfZQojA1wYW5lbGlzdF9uYW1llIwKUmV2aWV3ZXIgQZSMCmZvY3VzX2FyZWGUjCdDbGFpbSBQcmVjaXNpb24gJiBRdWFudGl0YXRpdmUgQWNjdXJhY3mUjAVzY29yZZRHQCIAAAAAAACMCXJlYXNvbmluZ5SMHVByZWNpc2lvbiBhbmFseXNpcyByZWFzb25pbmculGgrXZR1aBt9lGgdj5QoaCtoXWhbaF9oYJBoH051YmhXKYGUfZQoaAV9lChoW4wKUmV2aWV3ZXIgQpRoXYwHU291cmNlc5RoX0dAIgAAAAAAAGhgjBdTb3VyY2UgYXVkaXQgcmVhc29uaW5nLpRoK12UjA13ZWFrIHNvdXJjZSBBlGF1aBt9lGgdj5QoaCtoXWhbaF9oYJBoH051YmWMCmRlYmF0ZV9wcm+UaACMCkRlYmF0ZVNpZGWUk5QpgZR9lChoBX2UKIwEcm9sZZSMCEFkdm9jYXRllIwIYXJndW1lbnSUjCRTYXRlbGxpdGUgaW1hZ2VyeSBhbmQgZ2VvZGVzeSBhZ3JlZS6UjAhyZWJ1dHRhbJSMIkZsYXQtRWFydGggb2JqZWN0aW9ucyBkbyBub3QgaG9sZC6UdWgbfZRoHY+UKGh3aHlodZBoH051YowKZGViYXRlX2NvbpRocSmBlH2UKGgFfZQoaHWMB1NrZXB0aWOUaHeMIlRoZSBFYXJ0aCBpcyBub3QgYSBwZXJmZWN0IHNwaGVyZS6UaHmMIE9ibGF0ZSwgYnV0IHJvdW5kIGZvciB0aGUgY2xhaW0ulHVoG32UaB2PlChod2h5aHWQaB9OdWKMD3BhbmVsX2FncmVlbWVudJSMCXVuYW5pbW91c5R1aBt9lGgdj5QoaFRofWhSaIZob5BoH051YowKY3JlYXRlZF9hdJSMIDIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2KzAwOjAwlIwLbW9kaWZpZWRfYXSUTowIbGFuZ3VhZ2WUjAJlbpSMCGNvdmVyYWdllE51aBt9lGgdj5QoaAdoEWgkaIxoKWgLaA9oJ2gJaA1oimgiaCBoLmgraI1oj2gvaExoJpBoH051Yi4=", + "verify__verification_public_of_another_user.json": "gASVWwgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMBnB1YmxpY5SMBWRlcHRolIwIc3RhbmRhcmSUjAZkb21haW6UjAdTY2llbmNllIwIZW50aXRpZXOUXZRoAIwJRW50aXR5UmVmlJOUKYGUfZQoaAV9lCiMBG5hbWWUjAVFYXJ0aJSMA3FpZJROdYwSX19weWRhbnRpY19leHRyYV9flH2UjBdfX3B5ZGFudGljX2ZpZWxkc19zZXRfX5SPlChoGGgakIwUX19weWRhbnRpY19wcml2YXRlX1+UTnViYYwPcHJlc3VtZWRfaW50ZW50lIweVmVyaWZ5IGEgYmFzaWMgc2NpZW50aWZpYyBmYWN0lIwHdmVyZGljdJSMBFRydWWUjApjb25maWRlbmNllIwEaGlnaJSMCmxlbnpfc2NvcmWUSwmMC2tleV9maW5kaW5nlIwuVGhlIEVhcnRoIGlzIGFwcHJveGltYXRlbHkgc3BoZXJpY2FsIGluIHNoYXBlLpSMEWV4ZWN1dGl2ZV9zdW1tYXJ5lIwWVGhlIGNsYWltIGlzIHZlcmlmaWVkLpSMCHdhcm5pbmdzlF2UjBlSZWxpZXMgb24gbGltaXRlZCBzb3VyY2VzlGGMEXN1Z2dlc3RlZF9yZXdyaXRllE6MB3NvdXJjZXOUXZQoaACMBlNvdXJjZZSTlCmBlH2UKGgFfZQojAtzb3VyY2VfbmFtZZSMBE5BU0GUjAV0aXRsZZSMFlRoZSBzaGFwZSBvZiB0aGUgRWFydGiUjAN1cmyUjBpodHRwczovL25hc2EuZXhhbXBsZS9zaGFwZZSMB3NuaXBwZXSUjCtTYXRlbGxpdGUgaW1hZ2VyeSBzaG93cyBhbiBvYmxhdGUgc3BoZXJvaWQulIwEZGF0ZZSMCjIwMjUtMDEtMTWUdWgbfZRoHY+UKGg2aD5oOmg4aDyQaB9OdWJoMimBlH2UKGgFfZQoaDaMA0VTQZRoOIwQRWFydGggZnJvbSBzcGFjZZRoOowZaHR0cHM6Ly9lc2EuZXhhbXBsZS9lYXJ0aJRoPIwrT3JiaXRhbCBtZWFzdXJlbWVudHMgY29uZmlybSB0aGUgY3VydmF0dXJlLpRoPowKMjAyNS0wMS0xNpR1aBt9lGgdj5QoaDZoPmg6aDhoPJBoH051YmWMBWF1ZGl0lGgAjAVBdWRpdJSTlCmBlH2UKGgFfZQojBRhZGp1ZGljYXRpb25fc3VtbWFyeZSMFkJvdGggcmV2aWV3ZXJzIGFncmVlZC6UjAthc3Nlc3NtZW50c5RdlChoAIwKQXNzZXNzbWVudJSTlCmBlH2UKGgFfZQojA1wYW5lbGlzdF9uYW1llIwKUmV2aWV3ZXIgQZSMCmZvY3VzX2FyZWGUjCdDbGFpbSBQcmVjaXNpb24gJiBRdWFudGl0YXRpdmUgQWNjdXJhY3mUjAVzY29yZZRHQCIAAAAAAACMCXJlYXNvbmluZ5SMHVByZWNpc2lvbiBhbmFseXNpcyByZWFzb25pbmculGgrXZR1aBt9lGgdj5QoaCtoXWhbaF9oYJBoH051YmhXKYGUfZQoaAV9lChoW4wKUmV2aWV3ZXIgQpRoXYwHU291cmNlc5RoX0dAIgAAAAAAAGhgjBdTb3VyY2UgYXVkaXQgcmVhc29uaW5nLpRoK12UjA13ZWFrIHNvdXJjZSBBlGF1aBt9lGgdj5QoaCtoXWhbaF9oYJBoH051YmWMCmRlYmF0ZV9wcm+UaACMCkRlYmF0ZVNpZGWUk5QpgZR9lChoBX2UKIwEcm9sZZSMCEFkdm9jYXRllIwIYXJndW1lbnSUjCRTYXRlbGxpdGUgaW1hZ2VyeSBhbmQgZ2VvZGVzeSBhZ3JlZS6UjAhyZWJ1dHRhbJSMIkZsYXQtRWFydGggb2JqZWN0aW9ucyBkbyBub3QgaG9sZC6UdWgbfZRoHY+UKGh3aHlodZBoH051YowKZGViYXRlX2NvbpRocSmBlH2UKGgFfZQoaHWMB1NrZXB0aWOUaHeMIlRoZSBFYXJ0aCBpcyBub3QgYSBwZXJmZWN0IHNwaGVyZS6UaHmMIE9ibGF0ZSwgYnV0IHJvdW5kIGZvciB0aGUgY2xhaW0ulHVoG32UaB2PlChod2h5aHWQaB9OdWKMD3BhbmVsX2FncmVlbWVudJSMCXVuYW5pbW91c5R1aBt9lGgdj5QoaFRofWhSaIZob5BoH051YowKY3JlYXRlZF9hdJSMIDIwMjYtMTAtMDFUMDk6MDc6MDAuMTIzNDU2KzAwOjAwlIwLbW9kaWZpZWRfYXSUTowIbGFuZ3VhZ2WUjAJlbpSMCGNvdmVyYWdllGgAjAhDb3ZlcmFnZZSTlCmBlH2UKGgFfZQojAZzdGF0dXOUjAl1bmNvdmVyZWSUjAdyZWFzb25zlF2UjARwbGFulGGMDmNlcnRpZmljYXRlX2lklE6MD2NlcnRpZmljYXRlX3VybJROjAVhc19vZpROjAhjdXJyZW5jeZSMA0VVUpSMA2NhcJRNECeMCWFnZ3JlZ2F0ZZRKIKEHAIwNdGVybXNfdmVyc2lvbpSMAnYxlHVoG32UaB2PlChooGibaJ9onGiVaJ1ooWiaaJeQaB9OdWJ1aBt9lGgdj5QoaAdoEWgkaIxoKWgLaA9oJ2gJaA1oimgiaCBoLmgraI1oj2gvaExoJpBoH051Yi4=", + "verify__verification_zero_retention_served.json": "gASVZQgAAAAAAACMDmxlbnpfaW8ubW9kZWxzlIwMVmVyaWZpY2F0aW9ulJOUKYGUfZQojAhfX2RpY3RfX5R9lCiMD3ZlcmlmaWNhdGlvbl9pZJSMCDY4Y2E0YWFmlIwFY2xhaW2UjBNUaGUgRWFydGggaXMgcm91bmQulIwKdmlzaWJpbGl0eZSMB3ByaXZhdGWUjAVkZXB0aJSMCHN0YW5kYXJklIwGZG9tYWlulIwHU2NpZW5jZZSMCGVudGl0aWVzlF2UaACMCUVudGl0eVJlZpSTlCmBlH2UKGgFfZQojARuYW1llIwFRWFydGiUjANxaWSUTnWMEl9fcHlkYW50aWNfZXh0cmFfX5R9lIwXX19weWRhbnRpY19maWVsZHNfc2V0X1+Uj5QoaBhoGpCMFF9fcHlkYW50aWNfcHJpdmF0ZV9flE51YmGMD3ByZXN1bWVkX2ludGVudJSMHlZlcmlmeSBhIGJhc2ljIHNjaWVudGlmaWMgZmFjdJSMB3ZlcmRpY3SUjARUcnVllIwKY29uZmlkZW5jZZSMBGhpZ2iUjApsZW56X3Njb3JllEsJjAtrZXlfZmluZGluZ5SMJVRoZSBFYXJ0aCBpcyBhcHByb3hpbWF0ZWx5IHNwaGVyaWNhbC6UjBFleGVjdXRpdmVfc3VtbWFyeZSMKFRoZSBjbGFpbSBpcyB3ZWxsIHN1cHBvcnRlZCBieSBldmlkZW5jZS6UjAh3YXJuaW5nc5RdlIwZUmVsaWVzIG9uIGxpbWl0ZWQgc291cmNlc5RhjBFzdWdnZXN0ZWRfcmV3cml0ZZROjAdzb3VyY2VzlF2UKGgAjAZTb3VyY2WUk5QpgZR9lChoBX2UKIwLc291cmNlX25hbWWUjAROQVNBlIwFdGl0bGWUjBZUaGUgc2hhcGUgb2YgdGhlIEVhcnRolIwDdXJslIwaaHR0cHM6Ly9uYXNhLmV4YW1wbGUvc2hhcGWUjAdzbmlwcGV0lIwrU2F0ZWxsaXRlIGltYWdlcnkgc2hvd3MgYW4gb2JsYXRlIHNwaGVyb2lkLpSMBGRhdGWUjAoyMDI1LTAxLTE1lHVoG32UaB2PlChoNmg+aDpoOGg8kGgfTnViaDIpgZR9lChoBX2UKGg2jANFU0GUaDiMEEVhcnRoIGZyb20gc3BhY2WUaDqMGWh0dHBzOi8vZXNhLmV4YW1wbGUvZWFydGiUaDyMK09yYml0YWwgbWVhc3VyZW1lbnRzIGNvbmZpcm0gdGhlIGN1cnZhdHVyZS6UaD6MCjIwMjUtMDEtMTaUdWgbfZRoHY+UKGg2aD5oOmg4aDyQaB9OdWJljAVhdWRpdJRoAIwFQXVkaXSUk5QpgZR9lChoBX2UKIwUYWRqdWRpY2F0aW9uX3N1bW1hcnmUjBZCb3RoIHJldmlld2VycyBhZ3JlZWQulIwLYXNzZXNzbWVudHOUXZQoaACMCkFzc2Vzc21lbnSUk5QpgZR9lChoBX2UKIwNcGFuZWxpc3RfbmFtZZSMClJldmlld2VyIEGUjApmb2N1c19hcmVhlIwnQ2xhaW0gUHJlY2lzaW9uICYgUXVhbnRpdGF0aXZlIEFjY3VyYWN5lIwFc2NvcmWUR0AiAAAAAAAAjAlyZWFzb25pbmeUjB1QcmVjaXNpb24gYW5hbHlzaXMgcmVhc29uaW5nLpRoK12UdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJoVymBlH2UKGgFfZQoaFuMClJldmlld2VyIEKUaF2MB1NvdXJjZXOUaF9HQCIAAAAAAABoYIwXU291cmNlIGF1ZGl0IHJlYXNvbmluZy6UaCtdlIwNd2VhayBzb3VyY2UgQZRhdWgbfZRoHY+UKGgraF1oW2hfaGCQaB9OdWJljApkZWJhdGVfcHJvlGgAjApEZWJhdGVTaWRllJOUKYGUfZQoaAV9lCiMBHJvbGWUjAhBZHZvY2F0ZZSMCGFyZ3VtZW50lIwkU2F0ZWxsaXRlIGltYWdlcnkgYW5kIGdlb2Rlc3kgYWdyZWUulIwIcmVidXR0YWyUjCJGbGF0LUVhcnRoIG9iamVjdGlvbnMgZG8gbm90IGhvbGQulHVoG32UaB2PlChod2h5aHWQaB9OdWKMCmRlYmF0ZV9jb26UaHEpgZR9lChoBX2UKGh1jAdTa2VwdGljlGh3jCJUaGUgRWFydGggaXMgbm90IGEgcGVyZmVjdCBzcGhlcmUulGh5jCBPYmxhdGUsIGJ1dCByb3VuZCBmb3IgdGhlIGNsYWltLpR1aBt9lGgdj5QoaHdoeWh1kGgfTnVijA9wYW5lbF9hZ3JlZW1lbnSUjAl1bmFuaW1vdXOUdWgbfZRoHY+UKGhUaH1oUmiGaG+QaB9OdWKMCmNyZWF0ZWRfYXSUjCAyMDI2LTEwLTAxVDA5OjA3OjAwLjEyMzQ1NiswMDowMJSMC21vZGlmaWVkX2F0lE6MCGxhbmd1YWdllIwCZW6UjAhjb3ZlcmFnZZRoAIwIQ292ZXJhZ2WUk5QpgZR9lChoBX2UKIwGc3RhdHVzlIwJdW5jb3ZlcmVklIwHcmVhc29uc5RdlIwEcGxhbpRhjA5jZXJ0aWZpY2F0ZV9pZJROjA9jZXJ0aWZpY2F0ZV91cmyUTowFYXNfb2aUTowIY3VycmVuY3mUjANFVVKUjANjYXCUTRAnjAlhZ2dyZWdhdGWUSiChBwCMDXRlcm1zX3ZlcnNpb26UjAJ2MZR1aBt9lGgdj5QoaKBom2ifaJxolWidaKFommiXkGgfTnVidWgbfZRoHY+UKGgHaBFoJGiMaCloC2gPaCdoCWgNaIpoImggaC5oK2iNaI9oL2hMaCaQaB9OdWIu" +} diff --git a/tests/fixtures/parity/schemas.json b/tests/fixtures/parity/schemas.json new file mode 100644 index 0000000..4c8b1a6 --- /dev/null +++ b/tests/fixtures/parity/schemas.json @@ -0,0 +1,26564 @@ +{ + "AskHistory:serialization": { + "$defs": { + "AskMessage": { + "additionalProperties": true, + "description": "One message in an ``/ask`` conversation thread.", + "properties": { + "content": { + "default": "", + "title": "Content", + "type": "string" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "AskMessage", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Returned by ``GET /ask/{verification_id}``.", + "properties": { + "can_send": { + "default": false, + "title": "Can Send", + "type": "boolean" + }, + "exchange_limit": { + "default": 0, + "title": "Exchange Limit", + "type": "integer" + }, + "exchanges_used": { + "default": 0, + "title": "Exchanges Used", + "type": "integer" + }, + "messages": { + "items": { + "$ref": "#/$defs/AskMessage" + }, + "title": "Messages", + "type": "array" + } + }, + "title": "AskHistory", + "type": "object" + }, + "AskHistory:validation": { + "$defs": { + "AskMessage": { + "additionalProperties": true, + "description": "One message in an ``/ask`` conversation thread.", + "properties": { + "content": { + "default": "", + "title": "Content", + "type": "string" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "AskMessage", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Returned by ``GET /ask/{verification_id}``.", + "properties": { + "can_send": { + "default": false, + "title": "Can Send", + "type": "boolean" + }, + "exchange_limit": { + "default": 0, + "title": "Exchange Limit", + "type": "integer" + }, + "exchanges_used": { + "default": 0, + "title": "Exchanges Used", + "type": "integer" + }, + "messages": { + "items": { + "$ref": "#/$defs/AskMessage" + }, + "title": "Messages", + "type": "array" + } + }, + "title": "AskHistory", + "type": "object" + }, + "AskMessage:serialization": { + "additionalProperties": true, + "description": "One message in an ``/ask`` conversation thread.", + "properties": { + "content": { + "default": "", + "title": "Content", + "type": "string" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "AskMessage", + "type": "object" + }, + "AskMessage:validation": { + "additionalProperties": true, + "description": "One message in an ``/ask`` conversation thread.", + "properties": { + "content": { + "default": "", + "title": "Content", + "type": "string" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "AskMessage", + "type": "object" + }, + "AskReply:serialization": { + "additionalProperties": true, + "description": "Returned by ``POST /ask/{verification_id}``.\n\n``content`` is the assistant's reply text in a small markdown\nsubset:\n\n- ``**bold**`` and ``*italic*``\n- ``- `` or ``* `` bullet lists\n- Blank-line paragraph breaks; single newlines inside a paragraph\n mean line break\n\nThe model only produces these \u2014 no headings, no tables, no code\nblocks. Pass it through any markdown library or display it\nverbatim. See https://lenz.io/docs/quickstart#ask-reply-format.\n\nPre-1.0.2 the SDK declared a single ``reply`` field that never\nmatched the wire \u2014 the server has always returned\n``{role, content, created_at}``. 1.0.2 aligned the typed surface.", + "properties": { + "content": { + "default": "", + "title": "Content", + "type": "string" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "AskReply", + "type": "object" + }, + "AskReply:validation": { + "additionalProperties": true, + "description": "Returned by ``POST /ask/{verification_id}``.\n\n``content`` is the assistant's reply text in a small markdown\nsubset:\n\n- ``**bold**`` and ``*italic*``\n- ``- `` or ``* `` bullet lists\n- Blank-line paragraph breaks; single newlines inside a paragraph\n mean line break\n\nThe model only produces these \u2014 no headings, no tables, no code\nblocks. Pass it through any markdown library or display it\nverbatim. See https://lenz.io/docs/quickstart#ask-reply-format.\n\nPre-1.0.2 the SDK declared a single ``reply`` field that never\nmatched the wire \u2014 the server has always returned\n``{role, content, created_at}``. 1.0.2 aligned the typed surface.", + "properties": { + "content": { + "default": "", + "title": "Content", + "type": "string" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "AskReply", + "type": "object" + }, + "AssessClaim:serialization": { + "additionalProperties": true, + "description": "Per-claim entry in an ``AssessResponse.claims`` list.\n\nLean shape by design \u2014 no model_votes, no panel identity. The\n``verification_url`` (when present) points at the full\n``ClaimDetailOut`` payload at ``GET /api/v1/verifications/{id}`` for\ncallers that want citations and the full audit trail.\n\nA row with ``verdict == \"Error\"`` could not be given a verdict. On a\nlist call it stays in position (one row per item sent), is not charged,\nand says why: ``error_code`` names the cause and ``hint`` is one\nsentence on what to send next. ``hint`` is the field to surface to a\nhuman \u2014 it is written per cause and stays correct as causes are added.\nA vague input is assessed on its most likely reading, which ``claim``\ncarries. A compound input is assessed on its main claim; the other\nclaims found in it are listed in ``identified_claims`` (also with a\n``hint``). These fields default empty so older servers that don't send\nthem still parse.", + "properties": { + "candidate_claims": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidate Claims", + "type": "array" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "dissent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dissent" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error Code" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + } + }, + "title": "AssessClaim", + "type": "object" + }, + "AssessClaim:validation": { + "additionalProperties": true, + "description": "Per-claim entry in an ``AssessResponse.claims`` list.\n\nLean shape by design \u2014 no model_votes, no panel identity. The\n``verification_url`` (when present) points at the full\n``ClaimDetailOut`` payload at ``GET /api/v1/verifications/{id}`` for\ncallers that want citations and the full audit trail.\n\nA row with ``verdict == \"Error\"`` could not be given a verdict. On a\nlist call it stays in position (one row per item sent), is not charged,\nand says why: ``error_code`` names the cause and ``hint`` is one\nsentence on what to send next. ``hint`` is the field to surface to a\nhuman \u2014 it is written per cause and stays correct as causes are added.\nA vague input is assessed on its most likely reading, which ``claim``\ncarries. A compound input is assessed on its main claim; the other\nclaims found in it are listed in ``identified_claims`` (also with a\n``hint``). These fields default empty so older servers that don't send\nthem still parse.", + "properties": { + "candidate_claims": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidate Claims", + "type": "array" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "dissent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dissent" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error Code" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + } + }, + "title": "AssessClaim", + "type": "object" + }, + "AssessResponse:serialization": { + "$defs": { + "AssessClaim": { + "additionalProperties": true, + "description": "Per-claim entry in an ``AssessResponse.claims`` list.\n\nLean shape by design \u2014 no model_votes, no panel identity. The\n``verification_url`` (when present) points at the full\n``ClaimDetailOut`` payload at ``GET /api/v1/verifications/{id}`` for\ncallers that want citations and the full audit trail.\n\nA row with ``verdict == \"Error\"`` could not be given a verdict. On a\nlist call it stays in position (one row per item sent), is not charged,\nand says why: ``error_code`` names the cause and ``hint`` is one\nsentence on what to send next. ``hint`` is the field to surface to a\nhuman \u2014 it is written per cause and stays correct as causes are added.\nA vague input is assessed on its most likely reading, which ``claim``\ncarries. A compound input is assessed on its main claim; the other\nclaims found in it are listed in ``identified_claims`` (also with a\n``hint``). These fields default empty so older servers that don't send\nthem still parse.", + "properties": { + "candidate_claims": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidate Claims", + "type": "array" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "dissent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dissent" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error Code" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + } + }, + "title": "AssessClaim", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Output of ``POST /assess``.\n\nSingle form (``assess(claim=...)``): ``claims`` is one entry per claim\nfound in the input \u2014 up to 20, at 1 credit each. A text that makes more\nclaims than one call checks gets its most check-worthy 20 checked and the\nrest listed in ``more_claims``, unchecked and free: send them back with\n``assess(claims=...)``, 20 a call, to check them. ``error`` is set when\nthe input holds no checkable claim.\n\nList form (``assess(claims=[...])``): exactly one entry per item sent,\nin the order sent. An item that could not be given a verdict is an\n``\"Error\"`` row in position (see ``AssessClaim``), never a missing one;\nthe top-level ``error`` stays ``None``.\n\nWhen ``claims`` is empty (single form), ``error_code`` is ``'no_claim'``:\nthe input holds no checkable claim (a vague input is assessed on its\nmost likely reading instead). It defaults empty, so older servers that\ndon't send it degrade to the plain ``error`` message.", + "properties": { + "candidate_claims": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidate Claims", + "type": "array" + }, + "claims": { + "items": { + "$ref": "#/$defs/AssessClaim" + }, + "title": "Claims", + "type": "array" + }, + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error" + }, + "error_code": { + "default": "", + "title": "Error Code", + "type": "string" + }, + "more_claims": { + "items": { + "type": "string" + }, + "title": "More Claims", + "type": "array" + } + }, + "title": "AssessResponse", + "type": "object" + }, + "AssessResponse:validation": { + "$defs": { + "AssessClaim": { + "additionalProperties": true, + "description": "Per-claim entry in an ``AssessResponse.claims`` list.\n\nLean shape by design \u2014 no model_votes, no panel identity. The\n``verification_url`` (when present) points at the full\n``ClaimDetailOut`` payload at ``GET /api/v1/verifications/{id}`` for\ncallers that want citations and the full audit trail.\n\nA row with ``verdict == \"Error\"`` could not be given a verdict. On a\nlist call it stays in position (one row per item sent), is not charged,\nand says why: ``error_code`` names the cause and ``hint`` is one\nsentence on what to send next. ``hint`` is the field to surface to a\nhuman \u2014 it is written per cause and stays correct as causes are added.\nA vague input is assessed on its most likely reading, which ``claim``\ncarries. A compound input is assessed on its main claim; the other\nclaims found in it are listed in ``identified_claims`` (also with a\n``hint``). These fields default empty so older servers that don't send\nthem still parse.", + "properties": { + "candidate_claims": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidate Claims", + "type": "array" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "dissent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dissent" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error Code" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + } + }, + "title": "AssessClaim", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Output of ``POST /assess``.\n\nSingle form (``assess(claim=...)``): ``claims`` is one entry per claim\nfound in the input \u2014 up to 20, at 1 credit each. A text that makes more\nclaims than one call checks gets its most check-worthy 20 checked and the\nrest listed in ``more_claims``, unchecked and free: send them back with\n``assess(claims=...)``, 20 a call, to check them. ``error`` is set when\nthe input holds no checkable claim.\n\nList form (``assess(claims=[...])``): exactly one entry per item sent,\nin the order sent. An item that could not be given a verdict is an\n``\"Error\"`` row in position (see ``AssessClaim``), never a missing one;\nthe top-level ``error`` stays ``None``.\n\nWhen ``claims`` is empty (single form), ``error_code`` is ``'no_claim'``:\nthe input holds no checkable claim (a vague input is assessed on its\nmost likely reading instead). It defaults empty, so older servers that\ndon't send it degrade to the plain ``error`` message.", + "properties": { + "candidate_claims": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidate Claims", + "type": "array" + }, + "claims": { + "items": { + "$ref": "#/$defs/AssessClaim" + }, + "title": "Claims", + "type": "array" + }, + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error" + }, + "error_code": { + "default": "", + "title": "Error Code", + "type": "string" + }, + "more_claims": { + "items": { + "type": "string" + }, + "title": "More Claims", + "type": "array" + } + }, + "title": "AssessResponse", + "type": "object" + }, + "Assessment:serialization": { + "additionalProperties": true, + "description": "One reviewer's structured assessment.\n\nCurrent verifications carry three reviewers, ``Reviewer A`` to\n``Reviewer C``, all running the same checks over the evidence, plus\n``Reviewer D`` and ``Reviewer E`` when those three disagree. Their\n``focus_area`` reads ``\"Sources, evidence fit and wording\"``, and\n``warnings`` holds the source issues, evidence gaps and precision issues\nthat reviewer found, in one list.\n\nOlder verifications carry specialist panelists instead, one warning\ncategory each: logical fallacies (Logic Examiner), precision issues\n(Precision Analyst), weakest sources (Source Auditor) and, before\n2026-06, missing context (Context Analyst).\n\n``panelist_name`` is a display value, not a stable key \u2014 don't branch\non it. ``score`` is a reviewer-level 1-10 sub-score, distinct from the\ntop-level ``lenz_score`` on a ``Verification``.", + "properties": { + "focus_area": { + "default": "", + "title": "Focus Area", + "type": "string" + }, + "panelist_name": { + "default": "", + "title": "Panelist Name", + "type": "string" + }, + "reasoning": { + "default": "", + "title": "Reasoning", + "type": "string" + }, + "score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Score" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Assessment", + "type": "object" + }, + "Assessment:validation": { + "additionalProperties": true, + "description": "One reviewer's structured assessment.\n\nCurrent verifications carry three reviewers, ``Reviewer A`` to\n``Reviewer C``, all running the same checks over the evidence, plus\n``Reviewer D`` and ``Reviewer E`` when those three disagree. Their\n``focus_area`` reads ``\"Sources, evidence fit and wording\"``, and\n``warnings`` holds the source issues, evidence gaps and precision issues\nthat reviewer found, in one list.\n\nOlder verifications carry specialist panelists instead, one warning\ncategory each: logical fallacies (Logic Examiner), precision issues\n(Precision Analyst), weakest sources (Source Auditor) and, before\n2026-06, missing context (Context Analyst).\n\n``panelist_name`` is a display value, not a stable key \u2014 don't branch\non it. ``score`` is a reviewer-level 1-10 sub-score, distinct from the\ntop-level ``lenz_score`` on a ``Verification``.", + "properties": { + "focus_area": { + "default": "", + "title": "Focus Area", + "type": "string" + }, + "panelist_name": { + "default": "", + "title": "Panelist Name", + "type": "string" + }, + "reasoning": { + "default": "", + "title": "Reasoning", + "type": "string" + }, + "score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Score" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Assessment", + "type": "object" + }, + "Audit:serialization": { + "$defs": { + "Assessment": { + "additionalProperties": true, + "description": "One reviewer's structured assessment.\n\nCurrent verifications carry three reviewers, ``Reviewer A`` to\n``Reviewer C``, all running the same checks over the evidence, plus\n``Reviewer D`` and ``Reviewer E`` when those three disagree. Their\n``focus_area`` reads ``\"Sources, evidence fit and wording\"``, and\n``warnings`` holds the source issues, evidence gaps and precision issues\nthat reviewer found, in one list.\n\nOlder verifications carry specialist panelists instead, one warning\ncategory each: logical fallacies (Logic Examiner), precision issues\n(Precision Analyst), weakest sources (Source Auditor) and, before\n2026-06, missing context (Context Analyst).\n\n``panelist_name`` is a display value, not a stable key \u2014 don't branch\non it. ``score`` is a reviewer-level 1-10 sub-score, distinct from the\ntop-level ``lenz_score`` on a ``Verification``.", + "properties": { + "focus_area": { + "default": "", + "title": "Focus Area", + "type": "string" + }, + "panelist_name": { + "default": "", + "title": "Panelist Name", + "type": "string" + }, + "reasoning": { + "default": "", + "title": "Reasoning", + "type": "string" + }, + "score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Score" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Assessment", + "type": "object" + }, + "DebateSide": { + "additionalProperties": true, + "description": "One side of the adversarial debate transcript.", + "properties": { + "argument": { + "default": "", + "title": "Argument", + "type": "string" + }, + "rebuttal": { + "default": "", + "title": "Rebuttal", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "DebateSide", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Nested explainability block \u2014 for callers who want the panel's work.", + "properties": { + "adjudication_summary": { + "default": "", + "title": "Adjudication Summary", + "type": "string" + }, + "assessments": { + "items": { + "$ref": "#/$defs/Assessment" + }, + "title": "Assessments", + "type": "array" + }, + "debate_con": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "debate_pro": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "panel_agreement": { + "default": "", + "title": "Panel Agreement", + "type": "string" + } + }, + "title": "Audit", + "type": "object" + }, + "Audit:validation": { + "$defs": { + "Assessment": { + "additionalProperties": true, + "description": "One reviewer's structured assessment.\n\nCurrent verifications carry three reviewers, ``Reviewer A`` to\n``Reviewer C``, all running the same checks over the evidence, plus\n``Reviewer D`` and ``Reviewer E`` when those three disagree. Their\n``focus_area`` reads ``\"Sources, evidence fit and wording\"``, and\n``warnings`` holds the source issues, evidence gaps and precision issues\nthat reviewer found, in one list.\n\nOlder verifications carry specialist panelists instead, one warning\ncategory each: logical fallacies (Logic Examiner), precision issues\n(Precision Analyst), weakest sources (Source Auditor) and, before\n2026-06, missing context (Context Analyst).\n\n``panelist_name`` is a display value, not a stable key \u2014 don't branch\non it. ``score`` is a reviewer-level 1-10 sub-score, distinct from the\ntop-level ``lenz_score`` on a ``Verification``.", + "properties": { + "focus_area": { + "default": "", + "title": "Focus Area", + "type": "string" + }, + "panelist_name": { + "default": "", + "title": "Panelist Name", + "type": "string" + }, + "reasoning": { + "default": "", + "title": "Reasoning", + "type": "string" + }, + "score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Score" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Assessment", + "type": "object" + }, + "DebateSide": { + "additionalProperties": true, + "description": "One side of the adversarial debate transcript.", + "properties": { + "argument": { + "default": "", + "title": "Argument", + "type": "string" + }, + "rebuttal": { + "default": "", + "title": "Rebuttal", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "DebateSide", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Nested explainability block \u2014 for callers who want the panel's work.", + "properties": { + "adjudication_summary": { + "default": "", + "title": "Adjudication Summary", + "type": "string" + }, + "assessments": { + "items": { + "$ref": "#/$defs/Assessment" + }, + "title": "Assessments", + "type": "array" + }, + "debate_con": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "debate_pro": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "panel_agreement": { + "default": "", + "title": "Panel Agreement", + "type": "string" + } + }, + "title": "Audit", + "type": "object" + }, + "BatchAccepted:serialization": { + "$defs": { + "TaskAccepted": { + "additionalProperties": true, + "description": "Returned by ``POST /verify`` and per item of ``POST /verify/batch``.", + "properties": { + "claim_text": { + "default": "", + "title": "Claim Text", + "type": "string" + }, + "task_id": { + "default": "", + "title": "Task Id", + "type": "string" + } + }, + "title": "TaskAccepted", + "type": "object" + } + }, + "additionalProperties": true, + "properties": { + "batch_id": { + "default": "", + "title": "Batch Id", + "type": "string" + }, + "items": { + "items": { + "$ref": "#/$defs/TaskAccepted" + }, + "title": "Items", + "type": "array" + } + }, + "title": "BatchAccepted", + "type": "object" + }, + "BatchAccepted:validation": { + "$defs": { + "TaskAccepted": { + "additionalProperties": true, + "description": "Returned by ``POST /verify`` and per item of ``POST /verify/batch``.", + "properties": { + "claim_text": { + "default": "", + "title": "Claim Text", + "type": "string" + }, + "task_id": { + "default": "", + "title": "Task Id", + "type": "string" + } + }, + "title": "TaskAccepted", + "type": "object" + } + }, + "additionalProperties": true, + "properties": { + "batch_id": { + "default": "", + "title": "Batch Id", + "type": "string" + }, + "items": { + "items": { + "$ref": "#/$defs/TaskAccepted" + }, + "title": "Items", + "type": "array" + } + }, + "title": "BatchAccepted", + "type": "object" + }, + "BatchItemResult:serialization": { + "$defs": { + "Assessment": { + "additionalProperties": true, + "description": "One reviewer's structured assessment.\n\nCurrent verifications carry three reviewers, ``Reviewer A`` to\n``Reviewer C``, all running the same checks over the evidence, plus\n``Reviewer D`` and ``Reviewer E`` when those three disagree. Their\n``focus_area`` reads ``\"Sources, evidence fit and wording\"``, and\n``warnings`` holds the source issues, evidence gaps and precision issues\nthat reviewer found, in one list.\n\nOlder verifications carry specialist panelists instead, one warning\ncategory each: logical fallacies (Logic Examiner), precision issues\n(Precision Analyst), weakest sources (Source Auditor) and, before\n2026-06, missing context (Context Analyst).\n\n``panelist_name`` is a display value, not a stable key \u2014 don't branch\non it. ``score`` is a reviewer-level 1-10 sub-score, distinct from the\ntop-level ``lenz_score`` on a ``Verification``.", + "properties": { + "focus_area": { + "default": "", + "title": "Focus Area", + "type": "string" + }, + "panelist_name": { + "default": "", + "title": "Panelist Name", + "type": "string" + }, + "reasoning": { + "default": "", + "title": "Reasoning", + "type": "string" + }, + "score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Score" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Assessment", + "type": "object" + }, + "Audit": { + "additionalProperties": true, + "description": "Nested explainability block \u2014 for callers who want the panel's work.", + "properties": { + "adjudication_summary": { + "default": "", + "title": "Adjudication Summary", + "type": "string" + }, + "assessments": { + "items": { + "$ref": "#/$defs/Assessment" + }, + "title": "Assessments", + "type": "array" + }, + "debate_con": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "debate_pro": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "panel_agreement": { + "default": "", + "title": "Panel Agreement", + "type": "string" + } + }, + "title": "Audit", + "type": "object" + }, + "CandidateClaim": { + "additionalProperties": true, + "description": "One of multiple distinct claims framing found in the submitted text.", + "properties": { + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "CandidateClaim", + "type": "object" + }, + "Coverage": { + "additionalProperties": true, + "description": "Whether this verdict carries Lenz's warranty, for YOUR account.\n\nPresent only when covered verification is enabled on the account's plan;\n``None`` otherwise. It describes the pair (your account, this analysis),\nnot the analysis alone \u2014 two accounts can hold two certificates over one\ncached verdict, so the block you see is never another customer's.\n\n``reasons`` is empty exactly when ``status`` is not ``\"uncovered\"``.\n\nThe money fields are three, not two: ``currency`` is ISO 4217 and the\namounts are integers in **major units** \u2014 ``cap=10000`` means ten\nthousand, not a hundred. They are contract figures, not amounts a payment\nprocessor charges. Read ``currency``; do not assume EUR.", + "properties": { + "aggregate": { + "default": 0, + "title": "Aggregate", + "type": "integer" + }, + "as_of": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "As Of" + }, + "cap": { + "default": 0, + "title": "Cap", + "type": "integer" + }, + "certificate_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Id" + }, + "certificate_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Url" + }, + "currency": { + "default": "", + "title": "Currency", + "type": "string" + }, + "reasons": { + "items": { + "type": "string" + }, + "title": "Reasons", + "type": "array" + }, + "status": { + "default": "uncovered", + "title": "Status", + "type": "string" + }, + "terms_version": { + "default": "", + "title": "Terms Version", + "type": "string" + } + }, + "title": "Coverage", + "type": "object" + }, + "DebateSide": { + "additionalProperties": true, + "description": "One side of the adversarial debate transcript.", + "properties": { + "argument": { + "default": "", + "title": "Argument", + "type": "string" + }, + "rebuttal": { + "default": "", + "title": "Rebuttal", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "DebateSide", + "type": "object" + }, + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "Progress": { + "additionalProperties": true, + "description": "Where a running verification has got to. Advisory \u2014 never results.\n\n``step`` is one of ``starting`` / ``framing`` / ``research`` / ``debate``\n/ ``adjudication`` / ``conclusion``. ``index`` is the 1-based stage\nposition (0 while ``starting``) out of ``total``; read ``total`` off the\nresponse rather than hard-coding it. ``poll_after_seconds`` is how long\nto wait before looking again \u2014 :meth:`Lenz.verify_and_wait` honours it\nfor you. ``elapsed_seconds`` is how long the run has been going, a\nmeasurement rather than an estimate of what is left.\n\n``index`` is stage POSITION, not elapsed work: the stages are uneven, so\na bar driven by it sits on ``research`` for roughly half the run.\n\n``step`` stays a plain ``str``, not a ``Literal`` \u2014 an SDK that\nhard-rejects a stage name the server adds later is worse than one that\npasses it through.\n\nThis was a plain ``dict`` up to 2.10.0. The mapping methods below keep\n``p[\"step\"]``, ``\"step\" in p``, ``p.keys()`` and ``dict(p)`` working on a\n2.x minor; they are deprecated and go in 3.0.0. Use attributes.", + "properties": { + "elapsed_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Elapsed Seconds" + }, + "index": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Index" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "step": { + "default": "", + "title": "Step", + "type": "string" + }, + "total": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Total" + } + }, + "title": "Progress", + "type": "object" + }, + "SimilarVerification": { + "additionalProperties": true, + "description": "An existing public verification that semantically resembles the submitted text.\n\nSame vocabulary as ``Verification`` \u2014 flat ``verdict`` / ``confidence`` /\n``lenz_score`` at top level, no nested ``Verdict`` object.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "distance": { + "default": 0.0, + "title": "Distance", + "type": "number" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "SimilarVerification", + "type": "object" + }, + "Source": { + "additionalProperties": true, + "description": "A single citation backing a verification.", + "properties": { + "date": { + "default": "", + "title": "Date", + "type": "string" + }, + "snippet": { + "default": "", + "title": "Snippet", + "type": "string" + }, + "source_name": { + "default": "", + "title": "Source Name", + "type": "string" + }, + "title": { + "default": "", + "title": "Title", + "type": "string" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + } + }, + "title": "Source", + "type": "object" + }, + "TaskStatus": { + "additionalProperties": true, + "description": "Returned by ``GET /verify/status/{task_id}``.", + "properties": { + "candidates": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidates", + "type": "array" + }, + "claims": { + "items": { + "$ref": "#/$defs/CandidateClaim" + }, + "title": "Claims", + "type": "array" + }, + "docs_url": { + "default": "", + "title": "Docs Url", + "type": "string" + }, + "error": { + "default": "", + "title": "Error", + "type": "string" + }, + "failure_class": { + "default": "", + "title": "Failure Class", + "type": "string" + }, + "failure_detail": { + "default": "", + "title": "Failure Detail", + "type": "string" + }, + "failure_reason": { + "default": "", + "title": "Failure Reason", + "type": "string" + }, + "hint": { + "default": "", + "title": "Hint", + "type": "string" + }, + "progress": { + "$ref": "#/$defs/Progress" + }, + "reason": { + "default": "", + "title": "Reason", + "type": "string" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/Verification" + }, + { + "type": "null" + } + ], + "default": null + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + }, + "similar_claims": { + "deprecated": true, + "items": { + "$ref": "#/$defs/SimilarVerification" + }, + "title": "Similar Claims", + "type": "array" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "task_id": { + "default": "", + "title": "Task Id", + "type": "string" + } + }, + "title": "TaskStatus", + "type": "object" + }, + "Verification": { + "additionalProperties": true, + "description": "Full verification report \u2014 returned by ``verify_and_wait``,\n``verifications.get``, the ``/verify/status/{task_id}`` polling\nendpoint, and the webhook payload.\n\nThe verdict block is FLAT at top level (was nested ``Verdict`` object\npre-unify). ``created_at`` + ``modified_at`` are the only timestamp\nfields on the API surface \u2014 editorial ``published_at`` is internal-only.\n\n1.1.0: dropped ``url`` and ``visibility``. API claims are private by\ndefault and referenced by ``verification_id`` only. Cache-hit on\nanother customer's claim is transparent \u2014 the customer always sees\ntheir own ``verification_id``, never another customer's.\n\nLater: ``visibility`` returns \u2014 'private' | 'unlisted' | 'public'. It\nechoes what you set on submit ('private'/'unlisted' are settable;\n'public' can only be read, for listed claims). ``url`` stays dropped.", + "properties": { + "audit": { + "$ref": "#/$defs/Audit" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "coverage": { + "anyOf": [ + { + "$ref": "#/$defs/Coverage" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "default": "", + "title": "Depth", + "type": "string" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "presumed_intent": { + "default": "", + "title": "Presumed Intent", + "type": "string" + }, + "sources": { + "items": { + "$ref": "#/$defs/Source" + }, + "title": "Sources", + "type": "array" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + }, + "visibility": { + "default": "", + "title": "Visibility", + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Verification", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Per-item outcome from :meth:`Lenz.verify_batch_and_wait`.\n\nA client-side composition type \u2014 NOT a wire shape (the server never emits\nit, so it has no contract fixture). One entry per task that\n``POST /verify/batch`` returned, in input order.\n\n``status`` is a client-side rollup:\n\n- ``completed`` \u2014 ``verification`` is set (and ``status_detail`` carries the raw poll).\n- ``needs_input`` \u2014 paused for caller input; inspect ``status_detail`` (reason / claims).\n- ``failed`` \u2014 terminal failure (or completed-without-result); ``status_detail`` carries the diagnostic.\n A verification removed by its account's retention period (HTTP 410) is ``failed``, ``status_detail`` ``None``.\n- ``timeout`` \u2014 the deadline elapsed before this task reached a terminal state; ``status_detail`` is ``None``.", + "properties": { + "claim_text": { + "default": "", + "title": "Claim Text", + "type": "string" + }, + "status": { + "enum": [ + "completed", + "needs_input", + "failed", + "timeout" + ], + "title": "Status", + "type": "string" + }, + "status_detail": { + "anyOf": [ + { + "$ref": "#/$defs/TaskStatus" + }, + { + "type": "null" + } + ], + "default": null + }, + "task_id": { + "default": "", + "title": "Task Id", + "type": "string" + }, + "verification": { + "anyOf": [ + { + "$ref": "#/$defs/Verification" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "status" + ], + "title": "BatchItemResult", + "type": "object" + }, + "BatchItemResult:validation": { + "$defs": { + "Assessment": { + "additionalProperties": true, + "description": "One reviewer's structured assessment.\n\nCurrent verifications carry three reviewers, ``Reviewer A`` to\n``Reviewer C``, all running the same checks over the evidence, plus\n``Reviewer D`` and ``Reviewer E`` when those three disagree. Their\n``focus_area`` reads ``\"Sources, evidence fit and wording\"``, and\n``warnings`` holds the source issues, evidence gaps and precision issues\nthat reviewer found, in one list.\n\nOlder verifications carry specialist panelists instead, one warning\ncategory each: logical fallacies (Logic Examiner), precision issues\n(Precision Analyst), weakest sources (Source Auditor) and, before\n2026-06, missing context (Context Analyst).\n\n``panelist_name`` is a display value, not a stable key \u2014 don't branch\non it. ``score`` is a reviewer-level 1-10 sub-score, distinct from the\ntop-level ``lenz_score`` on a ``Verification``.", + "properties": { + "focus_area": { + "default": "", + "title": "Focus Area", + "type": "string" + }, + "panelist_name": { + "default": "", + "title": "Panelist Name", + "type": "string" + }, + "reasoning": { + "default": "", + "title": "Reasoning", + "type": "string" + }, + "score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Score" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Assessment", + "type": "object" + }, + "Audit": { + "additionalProperties": true, + "description": "Nested explainability block \u2014 for callers who want the panel's work.", + "properties": { + "adjudication_summary": { + "default": "", + "title": "Adjudication Summary", + "type": "string" + }, + "assessments": { + "items": { + "$ref": "#/$defs/Assessment" + }, + "title": "Assessments", + "type": "array" + }, + "debate_con": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "debate_pro": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "panel_agreement": { + "default": "", + "title": "Panel Agreement", + "type": "string" + } + }, + "title": "Audit", + "type": "object" + }, + "CandidateClaim": { + "additionalProperties": true, + "description": "One of multiple distinct claims framing found in the submitted text.", + "properties": { + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "CandidateClaim", + "type": "object" + }, + "Coverage": { + "additionalProperties": true, + "description": "Whether this verdict carries Lenz's warranty, for YOUR account.\n\nPresent only when covered verification is enabled on the account's plan;\n``None`` otherwise. It describes the pair (your account, this analysis),\nnot the analysis alone \u2014 two accounts can hold two certificates over one\ncached verdict, so the block you see is never another customer's.\n\n``reasons`` is empty exactly when ``status`` is not ``\"uncovered\"``.\n\nThe money fields are three, not two: ``currency`` is ISO 4217 and the\namounts are integers in **major units** \u2014 ``cap=10000`` means ten\nthousand, not a hundred. They are contract figures, not amounts a payment\nprocessor charges. Read ``currency``; do not assume EUR.", + "properties": { + "aggregate": { + "default": 0, + "title": "Aggregate", + "type": "integer" + }, + "as_of": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "As Of" + }, + "cap": { + "default": 0, + "title": "Cap", + "type": "integer" + }, + "certificate_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Id" + }, + "certificate_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Url" + }, + "currency": { + "default": "", + "title": "Currency", + "type": "string" + }, + "reasons": { + "items": { + "type": "string" + }, + "title": "Reasons", + "type": "array" + }, + "status": { + "default": "uncovered", + "title": "Status", + "type": "string" + }, + "terms_version": { + "default": "", + "title": "Terms Version", + "type": "string" + } + }, + "title": "Coverage", + "type": "object" + }, + "DebateSide": { + "additionalProperties": true, + "description": "One side of the adversarial debate transcript.", + "properties": { + "argument": { + "default": "", + "title": "Argument", + "type": "string" + }, + "rebuttal": { + "default": "", + "title": "Rebuttal", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "DebateSide", + "type": "object" + }, + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "Progress": { + "additionalProperties": true, + "description": "Where a running verification has got to. Advisory \u2014 never results.\n\n``step`` is one of ``starting`` / ``framing`` / ``research`` / ``debate``\n/ ``adjudication`` / ``conclusion``. ``index`` is the 1-based stage\nposition (0 while ``starting``) out of ``total``; read ``total`` off the\nresponse rather than hard-coding it. ``poll_after_seconds`` is how long\nto wait before looking again \u2014 :meth:`Lenz.verify_and_wait` honours it\nfor you. ``elapsed_seconds`` is how long the run has been going, a\nmeasurement rather than an estimate of what is left.\n\n``index`` is stage POSITION, not elapsed work: the stages are uneven, so\na bar driven by it sits on ``research`` for roughly half the run.\n\n``step`` stays a plain ``str``, not a ``Literal`` \u2014 an SDK that\nhard-rejects a stage name the server adds later is worse than one that\npasses it through.\n\nThis was a plain ``dict`` up to 2.10.0. The mapping methods below keep\n``p[\"step\"]``, ``\"step\" in p``, ``p.keys()`` and ``dict(p)`` working on a\n2.x minor; they are deprecated and go in 3.0.0. Use attributes.", + "properties": { + "elapsed_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Elapsed Seconds" + }, + "index": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Index" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "step": { + "default": "", + "title": "Step", + "type": "string" + }, + "total": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Total" + } + }, + "title": "Progress", + "type": "object" + }, + "SimilarVerification": { + "additionalProperties": true, + "description": "An existing public verification that semantically resembles the submitted text.\n\nSame vocabulary as ``Verification`` \u2014 flat ``verdict`` / ``confidence`` /\n``lenz_score`` at top level, no nested ``Verdict`` object.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "distance": { + "default": 0.0, + "title": "Distance", + "type": "number" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "SimilarVerification", + "type": "object" + }, + "Source": { + "additionalProperties": true, + "description": "A single citation backing a verification.", + "properties": { + "date": { + "default": "", + "title": "Date", + "type": "string" + }, + "snippet": { + "default": "", + "title": "Snippet", + "type": "string" + }, + "source_name": { + "default": "", + "title": "Source Name", + "type": "string" + }, + "title": { + "default": "", + "title": "Title", + "type": "string" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + } + }, + "title": "Source", + "type": "object" + }, + "TaskStatus": { + "additionalProperties": true, + "description": "Returned by ``GET /verify/status/{task_id}``.", + "properties": { + "candidates": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidates", + "type": "array" + }, + "claims": { + "items": { + "$ref": "#/$defs/CandidateClaim" + }, + "title": "Claims", + "type": "array" + }, + "docs_url": { + "default": "", + "title": "Docs Url", + "type": "string" + }, + "error": { + "default": "", + "title": "Error", + "type": "string" + }, + "failure_class": { + "default": "", + "title": "Failure Class", + "type": "string" + }, + "failure_detail": { + "default": "", + "title": "Failure Detail", + "type": "string" + }, + "failure_reason": { + "default": "", + "title": "Failure Reason", + "type": "string" + }, + "hint": { + "default": "", + "title": "Hint", + "type": "string" + }, + "progress": { + "$ref": "#/$defs/Progress" + }, + "reason": { + "default": "", + "title": "Reason", + "type": "string" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/Verification" + }, + { + "type": "null" + } + ], + "default": null + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + }, + "similar_claims": { + "deprecated": true, + "items": { + "$ref": "#/$defs/SimilarVerification" + }, + "title": "Similar Claims", + "type": "array" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "task_id": { + "default": "", + "title": "Task Id", + "type": "string" + } + }, + "title": "TaskStatus", + "type": "object" + }, + "Verification": { + "additionalProperties": true, + "description": "Full verification report \u2014 returned by ``verify_and_wait``,\n``verifications.get``, the ``/verify/status/{task_id}`` polling\nendpoint, and the webhook payload.\n\nThe verdict block is FLAT at top level (was nested ``Verdict`` object\npre-unify). ``created_at`` + ``modified_at`` are the only timestamp\nfields on the API surface \u2014 editorial ``published_at`` is internal-only.\n\n1.1.0: dropped ``url`` and ``visibility``. API claims are private by\ndefault and referenced by ``verification_id`` only. Cache-hit on\nanother customer's claim is transparent \u2014 the customer always sees\ntheir own ``verification_id``, never another customer's.\n\nLater: ``visibility`` returns \u2014 'private' | 'unlisted' | 'public'. It\nechoes what you set on submit ('private'/'unlisted' are settable;\n'public' can only be read, for listed claims). ``url`` stays dropped.", + "properties": { + "audit": { + "$ref": "#/$defs/Audit" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "coverage": { + "anyOf": [ + { + "$ref": "#/$defs/Coverage" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "default": "", + "title": "Depth", + "type": "string" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "presumed_intent": { + "default": "", + "title": "Presumed Intent", + "type": "string" + }, + "sources": { + "items": { + "$ref": "#/$defs/Source" + }, + "title": "Sources", + "type": "array" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + }, + "visibility": { + "default": "", + "title": "Visibility", + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Verification", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Per-item outcome from :meth:`Lenz.verify_batch_and_wait`.\n\nA client-side composition type \u2014 NOT a wire shape (the server never emits\nit, so it has no contract fixture). One entry per task that\n``POST /verify/batch`` returned, in input order.\n\n``status`` is a client-side rollup:\n\n- ``completed`` \u2014 ``verification`` is set (and ``status_detail`` carries the raw poll).\n- ``needs_input`` \u2014 paused for caller input; inspect ``status_detail`` (reason / claims).\n- ``failed`` \u2014 terminal failure (or completed-without-result); ``status_detail`` carries the diagnostic.\n A verification removed by its account's retention period (HTTP 410) is ``failed``, ``status_detail`` ``None``.\n- ``timeout`` \u2014 the deadline elapsed before this task reached a terminal state; ``status_detail`` is ``None``.", + "properties": { + "claim_text": { + "default": "", + "title": "Claim Text", + "type": "string" + }, + "status": { + "enum": [ + "completed", + "needs_input", + "failed", + "timeout" + ], + "title": "Status", + "type": "string" + }, + "status_detail": { + "anyOf": [ + { + "$ref": "#/$defs/TaskStatus" + }, + { + "type": "null" + } + ], + "default": null + }, + "task_id": { + "default": "", + "title": "Task Id", + "type": "string" + }, + "verification": { + "anyOf": [ + { + "$ref": "#/$defs/Verification" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "status" + ], + "title": "BatchItemResult", + "type": "object" + }, + "CandidateClaim:serialization": { + "additionalProperties": true, + "description": "One of multiple distinct claims framing found in the submitted text.", + "properties": { + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "CandidateClaim", + "type": "object" + }, + "CandidateClaim:validation": { + "additionalProperties": true, + "description": "One of multiple distinct claims framing found in the submitted text.", + "properties": { + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "CandidateClaim", + "type": "object" + }, + "Citecheck:serialization": { + "$defs": { + "CitecheckPolicy": { + "additionalProperties": true, + "description": "``max_citations``: how many citations are checked (for pairs, the\nnumber of pairs: every pair is checked).", + "properties": { + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + } + }, + "title": "CitecheckPolicy", + "type": "object" + }, + "CitecheckSummary": { + "additionalProperties": true, + "description": "Counts over the check, as on a review's ``summary``. ``citations_found``\nis the citations in the text, or the pairs sent; ``None`` until read.", + "properties": { + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + } + }, + "title": "CitecheckSummary", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewCitation": { + "additionalProperties": true, + "description": "One citation of the draft (a URL or a DOI where the draft uses it), in\nthe draft's order. Only on a review that asked for the citation check.\n\n``reference`` is the citation as the draft writes it; ``statement`` the\ndraft's sentence it is attached to, with link syntax reduced to its\nwords; ``quotes`` the words the draft quotes from this source.\n``position`` locates ``statement`` in the text as sent (its ``text`` is\n``None``: the row carries the ``statement``). ``result`` is\n``None`` until the check has ended, and on a failed row with nothing\nestablished.", + "properties": { + "check": { + "$ref": "#/$defs/ReviewCitationCheck" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationResult" + }, + { + "type": "null" + } + ], + "default": null + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitation", + "type": "object" + }, + "ReviewCitationCheck": { + "additionalProperties": true, + "description": "A citation's check. ``status`` is progress, as on ``assessment``:\n``pending`` | ``running`` | ``completed`` | ``failed``.\n\n- ``page_read``: ``full``, ``partial``, ``not_found`` or ``none``.\n- ``source_url``: where the text was actually read from (after\n redirects, or a free copy of a paper). ``source_version``, for a DOI:\n ``published``, ``accepted`` or ``submitted``.\n- ``support``: ``supported``, ``partly_supported``, ``contradicted``,\n ``not_in_source`` or ``unchecked``. ``snippet`` is the verified passage\n of the source it rests on; ``rationale`` is a reviewer's note, not a\n checked source.\n- ``quote``: ``matched``, ``not_in_source`` or ``unchecked``; ``None``\n when the draft quoted nothing from this source. ``missing_quote`` is\n the quoted excerpt the quote check did not find; ``None`` unless\n ``quote`` is ``not_in_source``.\n- ``doi_registered``, ``metadata`` (``consistent``, ``mismatch`` or\n ``unchecked``), ``metadata_differences`` and ``registered``: set for a\n DOI only.\n- ``unchecked_reason`` and ``hint``: why the finding is ``unchecked`` and\n what to do next. The reasons are an open set, e.g. ``no_text``,\n ``partial_text``, ``login_required``, ``unsupported_site``,\n ``no_statement``, ``invalid_url``, ``other_version``, ``inconclusive``,\n ``ambiguous_reference``.\n- ``failure``: on a ``failed`` check.", + "properties": { + "doi_registered": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi Registered" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "metadata": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Metadata" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Language" + }, + "page_published_date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Published Date" + }, + "page_read": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Read" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Quote" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "registered": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationRecord" + }, + { + "type": "null" + } + ], + "default": null + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Url" + }, + "source_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Version" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "support": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Support" + }, + "unchecked_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Unchecked Reason" + } + }, + "title": "ReviewCitationCheck", + "type": "object" + }, + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationFailure": { + "additionalProperties": true, + "description": "A citation whose check failed with nothing established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + } + }, + "title": "ReviewCitationFailure", + "type": "object" + }, + "ReviewCitationIssue": { + "additionalProperties": true, + "description": "A citation whose finding is an issue (see ``ReviewCitationResult``);\nmost serious first, then in the draft's order.\n\n``snippet`` and ``rationale`` are set only when ``source`` is\n``support``. On ``quote_not_in_source``, ``missing_quote`` is the quoted\nexcerpt that was not found. On ``metadata_mismatch``,\n``metadata_differences`` says what differs. ``failure`` is set when another part of the check failed after\nthe finding was established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitationIssue", + "type": "object" + }, + "ReviewCitationRecord": { + "additionalProperties": true, + "description": "A DOI's record in the registry.", + "properties": { + "authors": { + "items": { + "type": "string" + }, + "title": "Authors", + "type": "array" + }, + "journal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Journal" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "year": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Year" + } + }, + "title": "ReviewCitationRecord", + "type": "object" + }, + "ReviewCitationResult": { + "additionalProperties": true, + "description": "The one answer to read for a citation, derived from its ``check``.\n\n``finding``, most serious first: ``doi_not_found``, ``page_not_found``,\n``contradicted``, ``quote_not_in_source``, ``not_in_source``,\n``partly_supported``, ``metadata_mismatch`` (each an issue), then\n``supported`` and ``unchecked``. ``source`` says which check the finding\ncame from: ``doi``, ``page``, ``support``, ``quote`` or ``metadata``;\n``None`` on ``unchecked``.", + "properties": { + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + } + }, + "title": "ReviewCitationResult", + "type": "object" + }, + "ReviewCredits": { + "additionalProperties": true, + "description": "``charged`` is the net credits the review cost the account, its\ncitation checks included. It is final once no deep check or citation\ncheck is running: read it at ``completed``.", + "properties": { + "charged": { + "default": 0, + "title": "Charged", + "type": "integer" + } + }, + "title": "ReviewCredits", + "type": "object" + }, + "ReviewMoreCitation": { + "additionalProperties": true, + "description": "A citation found in the draft past the ones this review checked:\nfound but not checked. Send it in a later request to check it.\n``sentence`` is the draft's sentence around it.", + "properties": { + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "sentence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Sentence" + } + }, + "title": "ReviewMoreCitation", + "type": "object" + } + }, + "additionalProperties": true, + "description": "``GET /citechecks/{citecheck_id}``: a citation check as it stands.\n\n``status``: ``queued`` \u2192 ``checking`` \u2192 ``completed``, or ``failed``.\n``outcome`` is ``None`` until it ends, then ``clean``, ``issues_found``,\n``incomplete`` (a citation could not be checked for a reason of ours) or\n``unchecked``. ``citations``, ``citation_issues`` and ``citation_failures``\nare the review's rows. ``more_citations`` lists the citations of the text\npast the ones checked; ``None`` until the text is read, ``[]`` for pairs.", + "properties": { + "citation_failures": { + "items": { + "$ref": "#/$defs/ReviewCitationFailure" + }, + "title": "Citation Failures", + "type": "array" + }, + "citation_issues": { + "items": { + "$ref": "#/$defs/ReviewCitationIssue" + }, + "title": "Citation Issues", + "type": "array" + }, + "citations": { + "items": { + "$ref": "#/$defs/ReviewCitation" + }, + "title": "Citations", + "type": "array" + }, + "citecheck_id": { + "default": "", + "title": "Citecheck Id", + "type": "string" + }, + "completed_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Completed At" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "credits": { + "$ref": "#/$defs/ReviewCredits" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "more_citations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ReviewMoreCitation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Citations" + }, + "outcome": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Outcome" + }, + "policy": { + "$ref": "#/$defs/CitecheckPolicy" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "summary": { + "$ref": "#/$defs/CitecheckSummary" + } + }, + "title": "Citecheck", + "type": "object" + }, + "Citecheck:validation": { + "$defs": { + "CitecheckPolicy": { + "additionalProperties": true, + "description": "``max_citations``: how many citations are checked (for pairs, the\nnumber of pairs: every pair is checked).", + "properties": { + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + } + }, + "title": "CitecheckPolicy", + "type": "object" + }, + "CitecheckSummary": { + "additionalProperties": true, + "description": "Counts over the check, as on a review's ``summary``. ``citations_found``\nis the citations in the text, or the pairs sent; ``None`` until read.", + "properties": { + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + } + }, + "title": "CitecheckSummary", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewCitation": { + "additionalProperties": true, + "description": "One citation of the draft (a URL or a DOI where the draft uses it), in\nthe draft's order. Only on a review that asked for the citation check.\n\n``reference`` is the citation as the draft writes it; ``statement`` the\ndraft's sentence it is attached to, with link syntax reduced to its\nwords; ``quotes`` the words the draft quotes from this source.\n``position`` locates ``statement`` in the text as sent (its ``text`` is\n``None``: the row carries the ``statement``). ``result`` is\n``None`` until the check has ended, and on a failed row with nothing\nestablished.", + "properties": { + "check": { + "$ref": "#/$defs/ReviewCitationCheck" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationResult" + }, + { + "type": "null" + } + ], + "default": null + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitation", + "type": "object" + }, + "ReviewCitationCheck": { + "additionalProperties": true, + "description": "A citation's check. ``status`` is progress, as on ``assessment``:\n``pending`` | ``running`` | ``completed`` | ``failed``.\n\n- ``page_read``: ``full``, ``partial``, ``not_found`` or ``none``.\n- ``source_url``: where the text was actually read from (after\n redirects, or a free copy of a paper). ``source_version``, for a DOI:\n ``published``, ``accepted`` or ``submitted``.\n- ``support``: ``supported``, ``partly_supported``, ``contradicted``,\n ``not_in_source`` or ``unchecked``. ``snippet`` is the verified passage\n of the source it rests on; ``rationale`` is a reviewer's note, not a\n checked source.\n- ``quote``: ``matched``, ``not_in_source`` or ``unchecked``; ``None``\n when the draft quoted nothing from this source. ``missing_quote`` is\n the quoted excerpt the quote check did not find; ``None`` unless\n ``quote`` is ``not_in_source``.\n- ``doi_registered``, ``metadata`` (``consistent``, ``mismatch`` or\n ``unchecked``), ``metadata_differences`` and ``registered``: set for a\n DOI only.\n- ``unchecked_reason`` and ``hint``: why the finding is ``unchecked`` and\n what to do next. The reasons are an open set, e.g. ``no_text``,\n ``partial_text``, ``login_required``, ``unsupported_site``,\n ``no_statement``, ``invalid_url``, ``other_version``, ``inconclusive``,\n ``ambiguous_reference``.\n- ``failure``: on a ``failed`` check.", + "properties": { + "doi_registered": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi Registered" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "metadata": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Metadata" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Language" + }, + "page_published_date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Published Date" + }, + "page_read": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Read" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Quote" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "registered": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationRecord" + }, + { + "type": "null" + } + ], + "default": null + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Url" + }, + "source_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Version" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "support": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Support" + }, + "unchecked_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Unchecked Reason" + } + }, + "title": "ReviewCitationCheck", + "type": "object" + }, + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationFailure": { + "additionalProperties": true, + "description": "A citation whose check failed with nothing established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + } + }, + "title": "ReviewCitationFailure", + "type": "object" + }, + "ReviewCitationIssue": { + "additionalProperties": true, + "description": "A citation whose finding is an issue (see ``ReviewCitationResult``);\nmost serious first, then in the draft's order.\n\n``snippet`` and ``rationale`` are set only when ``source`` is\n``support``. On ``quote_not_in_source``, ``missing_quote`` is the quoted\nexcerpt that was not found. On ``metadata_mismatch``,\n``metadata_differences`` says what differs. ``failure`` is set when another part of the check failed after\nthe finding was established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitationIssue", + "type": "object" + }, + "ReviewCitationRecord": { + "additionalProperties": true, + "description": "A DOI's record in the registry.", + "properties": { + "authors": { + "items": { + "type": "string" + }, + "title": "Authors", + "type": "array" + }, + "journal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Journal" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "year": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Year" + } + }, + "title": "ReviewCitationRecord", + "type": "object" + }, + "ReviewCitationResult": { + "additionalProperties": true, + "description": "The one answer to read for a citation, derived from its ``check``.\n\n``finding``, most serious first: ``doi_not_found``, ``page_not_found``,\n``contradicted``, ``quote_not_in_source``, ``not_in_source``,\n``partly_supported``, ``metadata_mismatch`` (each an issue), then\n``supported`` and ``unchecked``. ``source`` says which check the finding\ncame from: ``doi``, ``page``, ``support``, ``quote`` or ``metadata``;\n``None`` on ``unchecked``.", + "properties": { + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + } + }, + "title": "ReviewCitationResult", + "type": "object" + }, + "ReviewCredits": { + "additionalProperties": true, + "description": "``charged`` is the net credits the review cost the account, its\ncitation checks included. It is final once no deep check or citation\ncheck is running: read it at ``completed``.", + "properties": { + "charged": { + "default": 0, + "title": "Charged", + "type": "integer" + } + }, + "title": "ReviewCredits", + "type": "object" + }, + "ReviewMoreCitation": { + "additionalProperties": true, + "description": "A citation found in the draft past the ones this review checked:\nfound but not checked. Send it in a later request to check it.\n``sentence`` is the draft's sentence around it.", + "properties": { + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "sentence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Sentence" + } + }, + "title": "ReviewMoreCitation", + "type": "object" + } + }, + "additionalProperties": true, + "description": "``GET /citechecks/{citecheck_id}``: a citation check as it stands.\n\n``status``: ``queued`` \u2192 ``checking`` \u2192 ``completed``, or ``failed``.\n``outcome`` is ``None`` until it ends, then ``clean``, ``issues_found``,\n``incomplete`` (a citation could not be checked for a reason of ours) or\n``unchecked``. ``citations``, ``citation_issues`` and ``citation_failures``\nare the review's rows. ``more_citations`` lists the citations of the text\npast the ones checked; ``None`` until the text is read, ``[]`` for pairs.", + "properties": { + "citation_failures": { + "items": { + "$ref": "#/$defs/ReviewCitationFailure" + }, + "title": "Citation Failures", + "type": "array" + }, + "citation_issues": { + "items": { + "$ref": "#/$defs/ReviewCitationIssue" + }, + "title": "Citation Issues", + "type": "array" + }, + "citations": { + "items": { + "$ref": "#/$defs/ReviewCitation" + }, + "title": "Citations", + "type": "array" + }, + "citecheck_id": { + "default": "", + "title": "Citecheck Id", + "type": "string" + }, + "completed_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Completed At" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "credits": { + "$ref": "#/$defs/ReviewCredits" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "more_citations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ReviewMoreCitation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Citations" + }, + "outcome": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Outcome" + }, + "policy": { + "$ref": "#/$defs/CitecheckPolicy" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "summary": { + "$ref": "#/$defs/CitecheckSummary" + } + }, + "title": "Citecheck", + "type": "object" + }, + "CitecheckPolicy:serialization": { + "additionalProperties": true, + "description": "``max_citations``: how many citations are checked (for pairs, the\nnumber of pairs: every pair is checked).", + "properties": { + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + } + }, + "title": "CitecheckPolicy", + "type": "object" + }, + "CitecheckPolicy:validation": { + "additionalProperties": true, + "description": "``max_citations``: how many citations are checked (for pairs, the\nnumber of pairs: every pair is checked).", + "properties": { + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + } + }, + "title": "CitecheckPolicy", + "type": "object" + }, + "CitecheckStarted:serialization": { + "additionalProperties": true, + "description": "Returned by ``POST /citecheck`` (HTTP 202). ``status`` is always\n``\"queued\"``: the receipt, not the current state.", + "properties": { + "citecheck_id": { + "default": "", + "title": "Citecheck Id", + "type": "string" + }, + "status": { + "default": "queued", + "title": "Status", + "type": "string" + } + }, + "title": "CitecheckStarted", + "type": "object" + }, + "CitecheckStarted:validation": { + "additionalProperties": true, + "description": "Returned by ``POST /citecheck`` (HTTP 202). ``status`` is always\n``\"queued\"``: the receipt, not the current state.", + "properties": { + "citecheck_id": { + "default": "", + "title": "Citecheck Id", + "type": "string" + }, + "status": { + "default": "queued", + "title": "Status", + "type": "string" + } + }, + "title": "CitecheckStarted", + "type": "object" + }, + "CitecheckSummary:serialization": { + "$defs": { + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Counts over the check, as on a review's ``summary``. ``citations_found``\nis the citations in the text, or the pairs sent; ``None`` until read.", + "properties": { + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + } + }, + "title": "CitecheckSummary", + "type": "object" + }, + "CitecheckSummary:validation": { + "$defs": { + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Counts over the check, as on a review's ``summary``. ``citations_found``\nis the citations in the text, or the pairs sent; ``None`` until read.", + "properties": { + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + } + }, + "title": "CitecheckSummary", + "type": "object" + }, + "ClaimLocation:serialization": { + "$defs": { + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Where the submitted text makes one claim.\n\n``claim`` is exactly as in the claim list it belongs to\n(``ExtractedClaims.claim`` / ``identified_claims``, or a review's\n``more_claims``). ``positions`` lists every place the text makes it, in\ntext order, at most 10. It is ``None`` only when that claim could not be\nplaced; on ``/extract`` every returned claim is placed.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + } + }, + "title": "ClaimLocation", + "type": "object" + }, + "ClaimLocation:validation": { + "$defs": { + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Where the submitted text makes one claim.\n\n``claim`` is exactly as in the claim list it belongs to\n(``ExtractedClaims.claim`` / ``identified_claims``, or a review's\n``more_claims``). ``positions`` lists every place the text makes it, in\ntext order, at most 10. It is ``None`` only when that claim could not be\nplaced; on ``/extract`` every returned claim is placed.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + } + }, + "title": "ClaimLocation", + "type": "object" + }, + "DebateSide:serialization": { + "additionalProperties": true, + "description": "One side of the adversarial debate transcript.", + "properties": { + "argument": { + "default": "", + "title": "Argument", + "type": "string" + }, + "rebuttal": { + "default": "", + "title": "Rebuttal", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "DebateSide", + "type": "object" + }, + "DebateSide:validation": { + "additionalProperties": true, + "description": "One side of the adversarial debate transcript.", + "properties": { + "argument": { + "default": "", + "title": "Argument", + "type": "string" + }, + "rebuttal": { + "default": "", + "title": "Rebuttal", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "DebateSide", + "type": "object" + }, + "EntityRef:serialization": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "EntityRef:validation": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "Escalation:serialization": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "Escalation:validation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "EscalationPolicy:serialization": { + "additionalProperties": true, + "description": "Which quick-checked claims get a deep check, as the review RESOLVED it.\n\nA claim is deep-checked when its quick verdict is in ``verdicts`` OR its\nconfidence band is in ``confidence``, up to ``max_verifications`` of them,\nat ``depth``. ``max_assessments`` is how many of the draft's claims, most\ncheck-worthy first, got a quick verdict.", + "properties": { + "confidence": { + "items": { + "type": "string" + }, + "title": "Confidence", + "type": "array" + }, + "depth": { + "default": "standard", + "title": "Depth", + "type": "string" + }, + "max_assessments": { + "default": 20, + "title": "Max Assessments", + "type": "integer" + }, + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + }, + "max_verifications": { + "default": 5, + "title": "Max Verifications", + "type": "integer" + }, + "suggest_edits": { + "default": false, + "title": "Suggest Edits", + "type": "boolean" + }, + "verdicts": { + "items": { + "type": "string" + }, + "title": "Verdicts", + "type": "array" + } + }, + "title": "EscalationPolicy", + "type": "object" + }, + "EscalationPolicy:validation": { + "additionalProperties": true, + "description": "Which quick-checked claims get a deep check, as the review RESOLVED it.\n\nA claim is deep-checked when its quick verdict is in ``verdicts`` OR its\nconfidence band is in ``confidence``, up to ``max_verifications`` of them,\nat ``depth``. ``max_assessments`` is how many of the draft's claims, most\ncheck-worthy first, got a quick verdict.", + "properties": { + "confidence": { + "items": { + "type": "string" + }, + "title": "Confidence", + "type": "array" + }, + "depth": { + "default": "standard", + "title": "Depth", + "type": "string" + }, + "max_assessments": { + "default": 20, + "title": "Max Assessments", + "type": "integer" + }, + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + }, + "max_verifications": { + "default": 5, + "title": "Max Verifications", + "type": "integer" + }, + "suggest_edits": { + "default": false, + "title": "Suggest Edits", + "type": "boolean" + }, + "verdicts": { + "items": { + "type": "string" + }, + "title": "Verdicts", + "type": "array" + } + }, + "title": "EscalationPolicy", + "type": "object" + }, + "ExtractedClaims:serialization": { + "$defs": { + "ClaimLocation": { + "additionalProperties": true, + "description": "Where the submitted text makes one claim.\n\n``claim`` is exactly as in the claim list it belongs to\n(``ExtractedClaims.claim`` / ``identified_claims``, or a review's\n``more_claims``). ``positions`` lists every place the text makes it, in\ntext order, at most 10. It is ``None`` only when that claim could not be\nplaced; on ``/extract`` every returned claim is placed.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + } + }, + "title": "ClaimLocation", + "type": "object" + }, + "ExtractedEntity": { + "additionalProperties": true, + "description": "An entity surfaced by ``/extract``. ``type`` is the framing category\n(``person`` | ``org`` | ``place`` | ``topic``).", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "type": { + "default": "", + "title": "Type", + "type": "string" + } + }, + "title": "ExtractedEntity", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Output of ``POST /extract``.\n\n``status`` is one of ``ExtractStatus``: ``ready``, ``not_a_claim``, or \u2014\nwhen a ``focus`` was given and no claim fell within it \u2014 ``no_match``.\n``no_match`` is a successful answer, not an error: ``identified_claims``\nis empty and the unfocused list is never substituted for it.\n\n``locations`` is set only on a call made with ``locate=True``: one\n``ClaimLocation`` per returned claim, in the order of\n``identified_claims`` (one entry for a single ``claim``). It is ``[]``\nwhen every claim was left out (``status`` is then ``\"not_a_claim\"``),\nand ``None`` when ``locate`` was not set, when the extraction found no\nclaims, or when the\nclaims could not be located (the list is then returned unfiltered).\nOlder servers omit the key; it parses as ``None``.", + "properties": { + "candidate_claims": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidate Claims", + "type": "array" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "key_entities": { + "items": { + "$ref": "#/$defs/ExtractedEntity" + }, + "title": "Key Entities", + "type": "array" + }, + "locations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ClaimLocation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Locations" + }, + "original_input": { + "default": "", + "title": "Original Input", + "type": "string" + }, + "presumed_intent": { + "default": "", + "title": "Presumed Intent", + "type": "string" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "ExtractedClaims", + "type": "object" + }, + "ExtractedClaims:validation": { + "$defs": { + "ClaimLocation": { + "additionalProperties": true, + "description": "Where the submitted text makes one claim.\n\n``claim`` is exactly as in the claim list it belongs to\n(``ExtractedClaims.claim`` / ``identified_claims``, or a review's\n``more_claims``). ``positions`` lists every place the text makes it, in\ntext order, at most 10. It is ``None`` only when that claim could not be\nplaced; on ``/extract`` every returned claim is placed.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + } + }, + "title": "ClaimLocation", + "type": "object" + }, + "ExtractedEntity": { + "additionalProperties": true, + "description": "An entity surfaced by ``/extract``. ``type`` is the framing category\n(``person`` | ``org`` | ``place`` | ``topic``).", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "type": { + "default": "", + "title": "Type", + "type": "string" + } + }, + "title": "ExtractedEntity", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Output of ``POST /extract``.\n\n``status`` is one of ``ExtractStatus``: ``ready``, ``not_a_claim``, or \u2014\nwhen a ``focus`` was given and no claim fell within it \u2014 ``no_match``.\n``no_match`` is a successful answer, not an error: ``identified_claims``\nis empty and the unfocused list is never substituted for it.\n\n``locations`` is set only on a call made with ``locate=True``: one\n``ClaimLocation`` per returned claim, in the order of\n``identified_claims`` (one entry for a single ``claim``). It is ``[]``\nwhen every claim was left out (``status`` is then ``\"not_a_claim\"``),\nand ``None`` when ``locate`` was not set, when the extraction found no\nclaims, or when the\nclaims could not be located (the list is then returned unfiltered).\nOlder servers omit the key; it parses as ``None``.", + "properties": { + "candidate_claims": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidate Claims", + "type": "array" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "key_entities": { + "items": { + "$ref": "#/$defs/ExtractedEntity" + }, + "title": "Key Entities", + "type": "array" + }, + "locations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ClaimLocation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Locations" + }, + "original_input": { + "default": "", + "title": "Original Input", + "type": "string" + }, + "presumed_intent": { + "default": "", + "title": "Presumed Intent", + "type": "string" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "ExtractedClaims", + "type": "object" + }, + "ExtractedEntity:serialization": { + "additionalProperties": true, + "description": "An entity surfaced by ``/extract``. ``type`` is the framing category\n(``person`` | ``org`` | ``place`` | ``topic``).", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "type": { + "default": "", + "title": "Type", + "type": "string" + } + }, + "title": "ExtractedEntity", + "type": "object" + }, + "ExtractedEntity:validation": { + "additionalProperties": true, + "description": "An entity surfaced by ``/extract``. ``type`` is the framing category\n(``person`` | ``org`` | ``place`` | ``topic``).", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "type": { + "default": "", + "title": "Type", + "type": "string" + } + }, + "title": "ExtractedEntity", + "type": "object" + }, + "FailureBlock:serialization": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "FailureBlock:validation": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "LibraryItem:serialization": { + "$defs": { + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Same shape as VerificationListItem on the public Library list.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "LibraryItem", + "type": "object" + }, + "LibraryItem:validation": { + "$defs": { + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Same shape as VerificationListItem on the public Library list.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "LibraryItem", + "type": "object" + }, + "LibraryList:serialization": { + "$defs": { + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "LibraryItem": { + "additionalProperties": true, + "description": "Same shape as VerificationListItem on the public Library list.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "LibraryItem", + "type": "object" + } + }, + "additionalProperties": true, + "properties": { + "items": { + "items": { + "$ref": "#/$defs/LibraryItem" + }, + "title": "Items", + "type": "array" + }, + "page": { + "default": 1, + "title": "Page", + "type": "integer" + }, + "page_size": { + "default": 20, + "title": "Page Size", + "type": "integer" + }, + "total": { + "default": 0, + "title": "Total", + "type": "integer" + } + }, + "title": "LibraryList", + "type": "object" + }, + "LibraryList:validation": { + "$defs": { + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "LibraryItem": { + "additionalProperties": true, + "description": "Same shape as VerificationListItem on the public Library list.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "LibraryItem", + "type": "object" + } + }, + "additionalProperties": true, + "properties": { + "items": { + "items": { + "$ref": "#/$defs/LibraryItem" + }, + "title": "Items", + "type": "array" + }, + "page": { + "default": 1, + "title": "Page", + "type": "integer" + }, + "page_size": { + "default": 20, + "title": "Page Size", + "type": "integer" + }, + "total": { + "default": 0, + "title": "Total", + "type": "integer" + } + }, + "title": "LibraryList", + "type": "object" + }, + "Position:serialization": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "Position:validation": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "RelatedVerifications:serialization": { + "$defs": { + "SimilarVerification": { + "additionalProperties": true, + "description": "An existing public verification that semantically resembles the submitted text.\n\nSame vocabulary as ``Verification`` \u2014 flat ``verdict`` / ``confidence`` /\n``lenz_score`` at top level, no nested ``Verdict`` object.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "distance": { + "default": 0.0, + "title": "Distance", + "type": "number" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "SimilarVerification", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Wrapper for ``GET /verifications/{id}/related``.", + "properties": { + "items": { + "items": { + "$ref": "#/$defs/SimilarVerification" + }, + "title": "Items", + "type": "array" + } + }, + "title": "RelatedVerifications", + "type": "object" + }, + "RelatedVerifications:validation": { + "$defs": { + "SimilarVerification": { + "additionalProperties": true, + "description": "An existing public verification that semantically resembles the submitted text.\n\nSame vocabulary as ``Verification`` \u2014 flat ``verdict`` / ``confidence`` /\n``lenz_score`` at top level, no nested ``Verdict`` object.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "distance": { + "default": 0.0, + "title": "Distance", + "type": "number" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "SimilarVerification", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Wrapper for ``GET /verifications/{id}/related``.", + "properties": { + "items": { + "items": { + "$ref": "#/$defs/SimilarVerification" + }, + "title": "Items", + "type": "array" + } + }, + "title": "RelatedVerifications", + "type": "object" + }, + "ReviewAssessment:serialization": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A claim's quick check. ``status``: ``pending`` | ``running`` |\n``completed`` | ``failed``. On ``completed`` the fields mean what they\nmean on an ``/assess`` row; on ``failed`` see ``error_code`` (an open\nset, as on ``/assess``), ``hint`` and ``failure``.", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "dissent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dissent" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error Code" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + } + }, + "title": "ReviewAssessment", + "type": "object" + }, + "ReviewAssessment:validation": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A claim's quick check. ``status``: ``pending`` | ``running`` |\n``completed`` | ``failed``. On ``completed`` the fields mean what they\nmean on an ``/assess`` row; on ``failed`` see ``error_code`` (an open\nset, as on ``/assess``), ``hint`` and ``failure``.", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "dissent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dissent" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error Code" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + } + }, + "title": "ReviewAssessment", + "type": "object" + }, + "ReviewAssessmentCounts:serialization": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + } + }, + "title": "ReviewAssessmentCounts", + "type": "object" + }, + "ReviewAssessmentCounts:validation": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + } + }, + "title": "ReviewAssessmentCounts", + "type": "object" + }, + "ReviewCitation:serialization": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewCitationCheck": { + "additionalProperties": true, + "description": "A citation's check. ``status`` is progress, as on ``assessment``:\n``pending`` | ``running`` | ``completed`` | ``failed``.\n\n- ``page_read``: ``full``, ``partial``, ``not_found`` or ``none``.\n- ``source_url``: where the text was actually read from (after\n redirects, or a free copy of a paper). ``source_version``, for a DOI:\n ``published``, ``accepted`` or ``submitted``.\n- ``support``: ``supported``, ``partly_supported``, ``contradicted``,\n ``not_in_source`` or ``unchecked``. ``snippet`` is the verified passage\n of the source it rests on; ``rationale`` is a reviewer's note, not a\n checked source.\n- ``quote``: ``matched``, ``not_in_source`` or ``unchecked``; ``None``\n when the draft quoted nothing from this source. ``missing_quote`` is\n the quoted excerpt the quote check did not find; ``None`` unless\n ``quote`` is ``not_in_source``.\n- ``doi_registered``, ``metadata`` (``consistent``, ``mismatch`` or\n ``unchecked``), ``metadata_differences`` and ``registered``: set for a\n DOI only.\n- ``unchecked_reason`` and ``hint``: why the finding is ``unchecked`` and\n what to do next. The reasons are an open set, e.g. ``no_text``,\n ``partial_text``, ``login_required``, ``unsupported_site``,\n ``no_statement``, ``invalid_url``, ``other_version``, ``inconclusive``,\n ``ambiguous_reference``.\n- ``failure``: on a ``failed`` check.", + "properties": { + "doi_registered": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi Registered" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "metadata": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Metadata" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Language" + }, + "page_published_date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Published Date" + }, + "page_read": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Read" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Quote" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "registered": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationRecord" + }, + { + "type": "null" + } + ], + "default": null + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Url" + }, + "source_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Version" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "support": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Support" + }, + "unchecked_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Unchecked Reason" + } + }, + "title": "ReviewCitationCheck", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationRecord": { + "additionalProperties": true, + "description": "A DOI's record in the registry.", + "properties": { + "authors": { + "items": { + "type": "string" + }, + "title": "Authors", + "type": "array" + }, + "journal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Journal" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "year": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Year" + } + }, + "title": "ReviewCitationRecord", + "type": "object" + }, + "ReviewCitationResult": { + "additionalProperties": true, + "description": "The one answer to read for a citation, derived from its ``check``.\n\n``finding``, most serious first: ``doi_not_found``, ``page_not_found``,\n``contradicted``, ``quote_not_in_source``, ``not_in_source``,\n``partly_supported``, ``metadata_mismatch`` (each an issue), then\n``supported`` and ``unchecked``. ``source`` says which check the finding\ncame from: ``doi``, ``page``, ``support``, ``quote`` or ``metadata``;\n``None`` on ``unchecked``.", + "properties": { + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + } + }, + "title": "ReviewCitationResult", + "type": "object" + } + }, + "additionalProperties": true, + "description": "One citation of the draft (a URL or a DOI where the draft uses it), in\nthe draft's order. Only on a review that asked for the citation check.\n\n``reference`` is the citation as the draft writes it; ``statement`` the\ndraft's sentence it is attached to, with link syntax reduced to its\nwords; ``quotes`` the words the draft quotes from this source.\n``position`` locates ``statement`` in the text as sent (its ``text`` is\n``None``: the row carries the ``statement``). ``result`` is\n``None`` until the check has ended, and on a failed row with nothing\nestablished.", + "properties": { + "check": { + "$ref": "#/$defs/ReviewCitationCheck" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationResult" + }, + { + "type": "null" + } + ], + "default": null + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitation", + "type": "object" + }, + "ReviewCitation:validation": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewCitationCheck": { + "additionalProperties": true, + "description": "A citation's check. ``status`` is progress, as on ``assessment``:\n``pending`` | ``running`` | ``completed`` | ``failed``.\n\n- ``page_read``: ``full``, ``partial``, ``not_found`` or ``none``.\n- ``source_url``: where the text was actually read from (after\n redirects, or a free copy of a paper). ``source_version``, for a DOI:\n ``published``, ``accepted`` or ``submitted``.\n- ``support``: ``supported``, ``partly_supported``, ``contradicted``,\n ``not_in_source`` or ``unchecked``. ``snippet`` is the verified passage\n of the source it rests on; ``rationale`` is a reviewer's note, not a\n checked source.\n- ``quote``: ``matched``, ``not_in_source`` or ``unchecked``; ``None``\n when the draft quoted nothing from this source. ``missing_quote`` is\n the quoted excerpt the quote check did not find; ``None`` unless\n ``quote`` is ``not_in_source``.\n- ``doi_registered``, ``metadata`` (``consistent``, ``mismatch`` or\n ``unchecked``), ``metadata_differences`` and ``registered``: set for a\n DOI only.\n- ``unchecked_reason`` and ``hint``: why the finding is ``unchecked`` and\n what to do next. The reasons are an open set, e.g. ``no_text``,\n ``partial_text``, ``login_required``, ``unsupported_site``,\n ``no_statement``, ``invalid_url``, ``other_version``, ``inconclusive``,\n ``ambiguous_reference``.\n- ``failure``: on a ``failed`` check.", + "properties": { + "doi_registered": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi Registered" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "metadata": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Metadata" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Language" + }, + "page_published_date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Published Date" + }, + "page_read": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Read" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Quote" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "registered": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationRecord" + }, + { + "type": "null" + } + ], + "default": null + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Url" + }, + "source_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Version" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "support": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Support" + }, + "unchecked_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Unchecked Reason" + } + }, + "title": "ReviewCitationCheck", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationRecord": { + "additionalProperties": true, + "description": "A DOI's record in the registry.", + "properties": { + "authors": { + "items": { + "type": "string" + }, + "title": "Authors", + "type": "array" + }, + "journal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Journal" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "year": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Year" + } + }, + "title": "ReviewCitationRecord", + "type": "object" + }, + "ReviewCitationResult": { + "additionalProperties": true, + "description": "The one answer to read for a citation, derived from its ``check``.\n\n``finding``, most serious first: ``doi_not_found``, ``page_not_found``,\n``contradicted``, ``quote_not_in_source``, ``not_in_source``,\n``partly_supported``, ``metadata_mismatch`` (each an issue), then\n``supported`` and ``unchecked``. ``source`` says which check the finding\ncame from: ``doi``, ``page``, ``support``, ``quote`` or ``metadata``;\n``None`` on ``unchecked``.", + "properties": { + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + } + }, + "title": "ReviewCitationResult", + "type": "object" + } + }, + "additionalProperties": true, + "description": "One citation of the draft (a URL or a DOI where the draft uses it), in\nthe draft's order. Only on a review that asked for the citation check.\n\n``reference`` is the citation as the draft writes it; ``statement`` the\ndraft's sentence it is attached to, with link syntax reduced to its\nwords; ``quotes`` the words the draft quotes from this source.\n``position`` locates ``statement`` in the text as sent (its ``text`` is\n``None``: the row carries the ``statement``). ``result`` is\n``None`` until the check has ended, and on a failed row with nothing\nestablished.", + "properties": { + "check": { + "$ref": "#/$defs/ReviewCitationCheck" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationResult" + }, + { + "type": "null" + } + ], + "default": null + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitation", + "type": "object" + }, + "ReviewCitationCheck:serialization": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationRecord": { + "additionalProperties": true, + "description": "A DOI's record in the registry.", + "properties": { + "authors": { + "items": { + "type": "string" + }, + "title": "Authors", + "type": "array" + }, + "journal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Journal" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "year": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Year" + } + }, + "title": "ReviewCitationRecord", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A citation's check. ``status`` is progress, as on ``assessment``:\n``pending`` | ``running`` | ``completed`` | ``failed``.\n\n- ``page_read``: ``full``, ``partial``, ``not_found`` or ``none``.\n- ``source_url``: where the text was actually read from (after\n redirects, or a free copy of a paper). ``source_version``, for a DOI:\n ``published``, ``accepted`` or ``submitted``.\n- ``support``: ``supported``, ``partly_supported``, ``contradicted``,\n ``not_in_source`` or ``unchecked``. ``snippet`` is the verified passage\n of the source it rests on; ``rationale`` is a reviewer's note, not a\n checked source.\n- ``quote``: ``matched``, ``not_in_source`` or ``unchecked``; ``None``\n when the draft quoted nothing from this source. ``missing_quote`` is\n the quoted excerpt the quote check did not find; ``None`` unless\n ``quote`` is ``not_in_source``.\n- ``doi_registered``, ``metadata`` (``consistent``, ``mismatch`` or\n ``unchecked``), ``metadata_differences`` and ``registered``: set for a\n DOI only.\n- ``unchecked_reason`` and ``hint``: why the finding is ``unchecked`` and\n what to do next. The reasons are an open set, e.g. ``no_text``,\n ``partial_text``, ``login_required``, ``unsupported_site``,\n ``no_statement``, ``invalid_url``, ``other_version``, ``inconclusive``,\n ``ambiguous_reference``.\n- ``failure``: on a ``failed`` check.", + "properties": { + "doi_registered": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi Registered" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "metadata": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Metadata" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Language" + }, + "page_published_date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Published Date" + }, + "page_read": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Read" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Quote" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "registered": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationRecord" + }, + { + "type": "null" + } + ], + "default": null + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Url" + }, + "source_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Version" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "support": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Support" + }, + "unchecked_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Unchecked Reason" + } + }, + "title": "ReviewCitationCheck", + "type": "object" + }, + "ReviewCitationCheck:validation": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationRecord": { + "additionalProperties": true, + "description": "A DOI's record in the registry.", + "properties": { + "authors": { + "items": { + "type": "string" + }, + "title": "Authors", + "type": "array" + }, + "journal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Journal" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "year": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Year" + } + }, + "title": "ReviewCitationRecord", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A citation's check. ``status`` is progress, as on ``assessment``:\n``pending`` | ``running`` | ``completed`` | ``failed``.\n\n- ``page_read``: ``full``, ``partial``, ``not_found`` or ``none``.\n- ``source_url``: where the text was actually read from (after\n redirects, or a free copy of a paper). ``source_version``, for a DOI:\n ``published``, ``accepted`` or ``submitted``.\n- ``support``: ``supported``, ``partly_supported``, ``contradicted``,\n ``not_in_source`` or ``unchecked``. ``snippet`` is the verified passage\n of the source it rests on; ``rationale`` is a reviewer's note, not a\n checked source.\n- ``quote``: ``matched``, ``not_in_source`` or ``unchecked``; ``None``\n when the draft quoted nothing from this source. ``missing_quote`` is\n the quoted excerpt the quote check did not find; ``None`` unless\n ``quote`` is ``not_in_source``.\n- ``doi_registered``, ``metadata`` (``consistent``, ``mismatch`` or\n ``unchecked``), ``metadata_differences`` and ``registered``: set for a\n DOI only.\n- ``unchecked_reason`` and ``hint``: why the finding is ``unchecked`` and\n what to do next. The reasons are an open set, e.g. ``no_text``,\n ``partial_text``, ``login_required``, ``unsupported_site``,\n ``no_statement``, ``invalid_url``, ``other_version``, ``inconclusive``,\n ``ambiguous_reference``.\n- ``failure``: on a ``failed`` check.", + "properties": { + "doi_registered": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi Registered" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "metadata": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Metadata" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Language" + }, + "page_published_date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Published Date" + }, + "page_read": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Read" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Quote" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "registered": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationRecord" + }, + { + "type": "null" + } + ], + "default": null + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Url" + }, + "source_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Version" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "support": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Support" + }, + "unchecked_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Unchecked Reason" + } + }, + "title": "ReviewCitationCheck", + "type": "object" + }, + "ReviewCitationCheckCounts:serialization": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewCitationCheckCounts:validation": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewCitationDifference:serialization": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationDifference:validation": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationFailure:serialization": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A citation whose check failed with nothing established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + } + }, + "title": "ReviewCitationFailure", + "type": "object" + }, + "ReviewCitationFailure:validation": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A citation whose check failed with nothing established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + } + }, + "title": "ReviewCitationFailure", + "type": "object" + }, + "ReviewCitationIssue:serialization": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A citation whose finding is an issue (see ``ReviewCitationResult``);\nmost serious first, then in the draft's order.\n\n``snippet`` and ``rationale`` are set only when ``source`` is\n``support``. On ``quote_not_in_source``, ``missing_quote`` is the quoted\nexcerpt that was not found. On ``metadata_mismatch``,\n``metadata_differences`` says what differs. ``failure`` is set when another part of the check failed after\nthe finding was established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitationIssue", + "type": "object" + }, + "ReviewCitationIssue:validation": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A citation whose finding is an issue (see ``ReviewCitationResult``);\nmost serious first, then in the draft's order.\n\n``snippet`` and ``rationale`` are set only when ``source`` is\n``support``. On ``quote_not_in_source``, ``missing_quote`` is the quoted\nexcerpt that was not found. On ``metadata_mismatch``,\n``metadata_differences`` says what differs. ``failure`` is set when another part of the check failed after\nthe finding was established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitationIssue", + "type": "object" + }, + "ReviewCitationRecord:serialization": { + "additionalProperties": true, + "description": "A DOI's record in the registry.", + "properties": { + "authors": { + "items": { + "type": "string" + }, + "title": "Authors", + "type": "array" + }, + "journal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Journal" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "year": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Year" + } + }, + "title": "ReviewCitationRecord", + "type": "object" + }, + "ReviewCitationRecord:validation": { + "additionalProperties": true, + "description": "A DOI's record in the registry.", + "properties": { + "authors": { + "items": { + "type": "string" + }, + "title": "Authors", + "type": "array" + }, + "journal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Journal" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "year": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Year" + } + }, + "title": "ReviewCitationRecord", + "type": "object" + }, + "ReviewCitationResult:serialization": { + "additionalProperties": true, + "description": "The one answer to read for a citation, derived from its ``check``.\n\n``finding``, most serious first: ``doi_not_found``, ``page_not_found``,\n``contradicted``, ``quote_not_in_source``, ``not_in_source``,\n``partly_supported``, ``metadata_mismatch`` (each an issue), then\n``supported`` and ``unchecked``. ``source`` says which check the finding\ncame from: ``doi``, ``page``, ``support``, ``quote`` or ``metadata``;\n``None`` on ``unchecked``.", + "properties": { + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + } + }, + "title": "ReviewCitationResult", + "type": "object" + }, + "ReviewCitationResult:validation": { + "additionalProperties": true, + "description": "The one answer to read for a citation, derived from its ``check``.\n\n``finding``, most serious first: ``doi_not_found``, ``page_not_found``,\n``contradicted``, ``quote_not_in_source``, ``not_in_source``,\n``partly_supported``, ``metadata_mismatch`` (each an issue), then\n``supported`` and ``unchecked``. ``source`` says which check the finding\ncame from: ``doi``, ``page``, ``support``, ``quote`` or ``metadata``;\n``None`` on ``unchecked``.", + "properties": { + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + } + }, + "title": "ReviewCitationResult", + "type": "object" + }, + "ReviewClaim:serialization": { + "$defs": { + "Escalation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewAssessment": { + "additionalProperties": true, + "description": "A claim's quick check. ``status``: ``pending`` | ``running`` |\n``completed`` | ``failed``. On ``completed`` the fields mean what they\nmean on an ``/assess`` row; on ``failed`` see ``error_code`` (an open\nset, as on ``/assess``), ``hint`` and ``failure``.", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "dissent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dissent" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error Code" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + } + }, + "title": "ReviewAssessment", + "type": "object" + }, + "ReviewEntity": { + "additionalProperties": true, + "description": "An entity the deep check found in the claim. ``qid`` is its Wikidata\nid when resolved. Either may be ``None``.", + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "ReviewEntity", + "type": "object" + }, + "ReviewResult": { + "additionalProperties": true, + "description": "The one answer to read for a claim: the deep check's verdict when it\ncompleted, else the quick check's. ``source`` says which\n(``assessment`` or ``verification``).", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + } + }, + "title": "ReviewResult", + "type": "object" + }, + "ReviewVerification": { + "additionalProperties": true, + "description": "A claim's deep check. ``status``: ``processing`` | ``completed`` |\n``failed``; while ``processing`` only ``status``, ``content_status`` and\nthe ids are set. ``content_status`` is ``purged`` once the verification\nwas deleted or removed by its account's retention period: the verdict and\nids stay, the text fields and links are ``None``.\n\n``visibility`` and ``depth`` are what the verification actually has: a\nverdict served from an earlier check keeps its own visibility and may be\n``standard`` for a ``low`` request. Sources are on the verification\nitself: ``client.verifications.get(verification_id)``, or ``url``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "content_status": { + "default": "available", + "title": "Content Status", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Depth" + }, + "domain": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Domain" + }, + "entities": { + "items": { + "$ref": "#/$defs/ReviewEntity" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Executive Summary" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Language" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "task_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Task Id" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "visibility": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Visibility" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "ReviewVerification", + "type": "object" + }, + "SuggestedEdit": { + "additionalProperties": true, + "description": "One replacement in the draft: the span ``start``..``end`` of the\n``text`` you sent (Unicode code points, ``end`` exclusive, as in\n``Position``), ``text`` exactly that slice, and ``replacement`` what takes\nits place (``\"\"`` deletes it). ``position`` is the index of the claim\nrow's ``positions`` entry the edit sits in, for grouping by passage.\n\nCompare ``text`` with your draft before you apply an edit, so a draft that\nchanged since is never edited in the wrong place.", + "properties": { + "end": { + "default": 0, + "title": "End", + "type": "integer" + }, + "position": { + "default": 0, + "title": "Position", + "type": "integer" + }, + "replacement": { + "default": "", + "title": "Replacement", + "type": "string" + }, + "start": { + "default": 0, + "title": "Start", + "type": "integer" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "SuggestedEdit", + "type": "object" + }, + "SuggestedEdits": { + "additionalProperties": true, + "description": "The smallest edits to the draft that make it say what the claim's\n``suggested_rewrite`` says (the deep check's, or the quick check's on a\nclaim that stayed on the quick verdict), in the draft's own language\n(``review(..., suggest_edits=True)``).\n\n``status`` is ``\"pending\"`` while they are computed (``edits`` is\n``None``; keep polling) and ``\"completed\"`` once settled, which includes\nsettling on none (``edits == []``: no edit could be made safely, or it\ncould not be computed). They are not themselves verified:\nreview them before you publish.", + "properties": { + "edits": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/SuggestedEdit" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Edits" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "SuggestedEdits", + "type": "object" + } + }, + "additionalProperties": true, + "description": "One claim of the draft, in the order the draft's claims were read.\n\n``result`` is ``None`` until the quick check completes, and on a failed\none. ``escalation`` is ``None`` until then too. ``verification`` is set\nonce a deep check was planned for the claim.\n\n``positions`` lists every place the draft makes the claim, in text\norder, at most 10 (see ``Position``). ``start`` / ``end`` index the\n``text`` you sent in Unicode code points (``text[start:end]`` in Python;\n``end`` exclusive), the same coordinates as a citation's ``position``.\nFor a URL draft, ``start`` and ``end`` are ``None`` and ``text`` carries\nthe passage. ``positions`` is ``None`` when the claims could not be\nlocated, or once a zero-retention draft is gone (and from servers that\npredate the field).", + "properties": { + "assessment": { + "$ref": "#/$defs/ReviewAssessment" + }, + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewResult" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "verification": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerification" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewClaim", + "type": "object" + }, + "ReviewClaim:validation": { + "$defs": { + "Escalation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewAssessment": { + "additionalProperties": true, + "description": "A claim's quick check. ``status``: ``pending`` | ``running`` |\n``completed`` | ``failed``. On ``completed`` the fields mean what they\nmean on an ``/assess`` row; on ``failed`` see ``error_code`` (an open\nset, as on ``/assess``), ``hint`` and ``failure``.", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "dissent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dissent" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error Code" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + } + }, + "title": "ReviewAssessment", + "type": "object" + }, + "ReviewEntity": { + "additionalProperties": true, + "description": "An entity the deep check found in the claim. ``qid`` is its Wikidata\nid when resolved. Either may be ``None``.", + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "ReviewEntity", + "type": "object" + }, + "ReviewResult": { + "additionalProperties": true, + "description": "The one answer to read for a claim: the deep check's verdict when it\ncompleted, else the quick check's. ``source`` says which\n(``assessment`` or ``verification``).", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + } + }, + "title": "ReviewResult", + "type": "object" + }, + "ReviewVerification": { + "additionalProperties": true, + "description": "A claim's deep check. ``status``: ``processing`` | ``completed`` |\n``failed``; while ``processing`` only ``status``, ``content_status`` and\nthe ids are set. ``content_status`` is ``purged`` once the verification\nwas deleted or removed by its account's retention period: the verdict and\nids stay, the text fields and links are ``None``.\n\n``visibility`` and ``depth`` are what the verification actually has: a\nverdict served from an earlier check keeps its own visibility and may be\n``standard`` for a ``low`` request. Sources are on the verification\nitself: ``client.verifications.get(verification_id)``, or ``url``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "content_status": { + "default": "available", + "title": "Content Status", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Depth" + }, + "domain": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Domain" + }, + "entities": { + "items": { + "$ref": "#/$defs/ReviewEntity" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Executive Summary" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Language" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "task_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Task Id" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "visibility": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Visibility" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "ReviewVerification", + "type": "object" + }, + "SuggestedEdit": { + "additionalProperties": true, + "description": "One replacement in the draft: the span ``start``..``end`` of the\n``text`` you sent (Unicode code points, ``end`` exclusive, as in\n``Position``), ``text`` exactly that slice, and ``replacement`` what takes\nits place (``\"\"`` deletes it). ``position`` is the index of the claim\nrow's ``positions`` entry the edit sits in, for grouping by passage.\n\nCompare ``text`` with your draft before you apply an edit, so a draft that\nchanged since is never edited in the wrong place.", + "properties": { + "end": { + "default": 0, + "title": "End", + "type": "integer" + }, + "position": { + "default": 0, + "title": "Position", + "type": "integer" + }, + "replacement": { + "default": "", + "title": "Replacement", + "type": "string" + }, + "start": { + "default": 0, + "title": "Start", + "type": "integer" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "SuggestedEdit", + "type": "object" + }, + "SuggestedEdits": { + "additionalProperties": true, + "description": "The smallest edits to the draft that make it say what the claim's\n``suggested_rewrite`` says (the deep check's, or the quick check's on a\nclaim that stayed on the quick verdict), in the draft's own language\n(``review(..., suggest_edits=True)``).\n\n``status`` is ``\"pending\"`` while they are computed (``edits`` is\n``None``; keep polling) and ``\"completed\"`` once settled, which includes\nsettling on none (``edits == []``: no edit could be made safely, or it\ncould not be computed). They are not themselves verified:\nreview them before you publish.", + "properties": { + "edits": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/SuggestedEdit" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Edits" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "SuggestedEdits", + "type": "object" + } + }, + "additionalProperties": true, + "description": "One claim of the draft, in the order the draft's claims were read.\n\n``result`` is ``None`` until the quick check completes, and on a failed\none. ``escalation`` is ``None`` until then too. ``verification`` is set\nonce a deep check was planned for the claim.\n\n``positions`` lists every place the draft makes the claim, in text\norder, at most 10 (see ``Position``). ``start`` / ``end`` index the\n``text`` you sent in Unicode code points (``text[start:end]`` in Python;\n``end`` exclusive), the same coordinates as a citation's ``position``.\nFor a URL draft, ``start`` and ``end`` are ``None`` and ``text`` carries\nthe passage. ``positions`` is ``None`` when the claims could not be\nlocated, or once a zero-retention draft is gone (and from servers that\npredate the field).", + "properties": { + "assessment": { + "$ref": "#/$defs/ReviewAssessment" + }, + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewResult" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "verification": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerification" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewClaim", + "type": "object" + }, + "ReviewCredits:serialization": { + "additionalProperties": true, + "description": "``charged`` is the net credits the review cost the account, its\ncitation checks included. It is final once no deep check or citation\ncheck is running: read it at ``completed``.", + "properties": { + "charged": { + "default": 0, + "title": "Charged", + "type": "integer" + } + }, + "title": "ReviewCredits", + "type": "object" + }, + "ReviewCredits:validation": { + "additionalProperties": true, + "description": "``charged`` is the net credits the review cost the account, its\ncitation checks included. It is final once no deep check or citation\ncheck is running: read it at ``completed``.", + "properties": { + "charged": { + "default": 0, + "title": "Charged", + "type": "integer" + } + }, + "title": "ReviewCredits", + "type": "object" + }, + "ReviewEntity:serialization": { + "additionalProperties": true, + "description": "An entity the deep check found in the claim. ``qid`` is its Wikidata\nid when resolved. Either may be ``None``.", + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "ReviewEntity", + "type": "object" + }, + "ReviewEntity:validation": { + "additionalProperties": true, + "description": "An entity the deep check found in the claim. ``qid`` is its Wikidata\nid when resolved. Either may be ``None``.", + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "ReviewEntity", + "type": "object" + }, + "ReviewEnvelope:serialization": { + "$defs": { + "ClaimLocation": { + "additionalProperties": true, + "description": "Where the submitted text makes one claim.\n\n``claim`` is exactly as in the claim list it belongs to\n(``ExtractedClaims.claim`` / ``identified_claims``, or a review's\n``more_claims``). ``positions`` lists every place the text makes it, in\ntext order, at most 10. It is ``None`` only when that claim could not be\nplaced; on ``/extract`` every returned claim is placed.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + } + }, + "title": "ClaimLocation", + "type": "object" + }, + "Escalation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "EscalationPolicy": { + "additionalProperties": true, + "description": "Which quick-checked claims get a deep check, as the review RESOLVED it.\n\nA claim is deep-checked when its quick verdict is in ``verdicts`` OR its\nconfidence band is in ``confidence``, up to ``max_verifications`` of them,\nat ``depth``. ``max_assessments`` is how many of the draft's claims, most\ncheck-worthy first, got a quick verdict.", + "properties": { + "confidence": { + "items": { + "type": "string" + }, + "title": "Confidence", + "type": "array" + }, + "depth": { + "default": "standard", + "title": "Depth", + "type": "string" + }, + "max_assessments": { + "default": 20, + "title": "Max Assessments", + "type": "integer" + }, + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + }, + "max_verifications": { + "default": 5, + "title": "Max Verifications", + "type": "integer" + }, + "suggest_edits": { + "default": false, + "title": "Suggest Edits", + "type": "boolean" + }, + "verdicts": { + "items": { + "type": "string" + }, + "title": "Verdicts", + "type": "array" + } + }, + "title": "EscalationPolicy", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewAssessmentCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + } + }, + "title": "ReviewAssessmentCounts", + "type": "object" + }, + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationFailure": { + "additionalProperties": true, + "description": "A citation whose check failed with nothing established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + } + }, + "title": "ReviewCitationFailure", + "type": "object" + }, + "ReviewCitationIssue": { + "additionalProperties": true, + "description": "A citation whose finding is an issue (see ``ReviewCitationResult``);\nmost serious first, then in the draft's order.\n\n``snippet`` and ``rationale`` are set only when ``source`` is\n``support``. On ``quote_not_in_source``, ``missing_quote`` is the quoted\nexcerpt that was not found. On ``metadata_mismatch``,\n``metadata_differences`` says what differs. ``failure`` is set when another part of the check failed after\nthe finding was established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitationIssue", + "type": "object" + }, + "ReviewCredits": { + "additionalProperties": true, + "description": "``charged`` is the net credits the review cost the account, its\ncitation checks included. It is final once no deep check or citation\ncheck is running: read it at ``completed``.", + "properties": { + "charged": { + "default": 0, + "title": "Charged", + "type": "integer" + } + }, + "title": "ReviewCredits", + "type": "object" + }, + "ReviewFailure": { + "additionalProperties": true, + "description": "A claim outside the issues whose work failed. ``stage`` is\n``assessment`` or ``verification``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "stage": { + "default": "", + "title": "Stage", + "type": "string" + } + }, + "title": "ReviewFailure", + "type": "object" + }, + "ReviewIssue": { + "additionalProperties": true, + "description": "A claim whose final verdict is ``False``, ``Mostly False`` or ``Mixed``.\n\n``source`` says which check the verdict comes from: ``verification`` (a\ndeep check, with ``verification_id``, ``url`` and ``key_finding``) or\n``assessment`` (the quick check only; ``escalation`` says why it was not\ndeep-checked, and ``rationale`` is the reviewers' note).\n``verified_claim`` is the deep check's wording of the claim when it\ndiffers from ``claim``. ``failure`` is set when the claim's deep check\nfailed.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_status": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Status" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "verified_claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verified Claim" + } + }, + "title": "ReviewIssue", + "type": "object" + }, + "ReviewMoreCitation": { + "additionalProperties": true, + "description": "A citation found in the draft past the ones this review checked:\nfound but not checked. Send it in a later request to check it.\n``sentence`` is the draft's sentence around it.", + "properties": { + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "sentence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Sentence" + } + }, + "title": "ReviewMoreCitation", + "type": "object" + }, + "ReviewSummary": { + "additionalProperties": true, + "description": "Counts over the review. A count is ``None`` until what it counts is\nknown (``claims_selected`` before the draft has been read).\n\nThe ``citation*`` counts are ``None`` (``citation_issues`` 0) on a review\nthat did not ask for the citation check.", + "properties": { + "assessments": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewAssessmentCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + }, + "citations_skipped": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Skipped" + }, + "claim_limit": { + "default": 20, + "title": "Claim Limit", + "type": "integer" + }, + "claim_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim Limit Reached" + }, + "claims_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claims Selected" + }, + "input_truncated": { + "default": false, + "title": "Input Truncated", + "type": "boolean" + }, + "issues": { + "default": 0, + "title": "Issues", + "type": "integer" + }, + "verifications": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerificationCounts" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewSummary", + "type": "object" + }, + "ReviewVerificationCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "planned": { + "default": 0, + "title": "Planned", + "type": "integer" + } + }, + "title": "ReviewVerificationCounts", + "type": "object" + }, + "SuggestedEdit": { + "additionalProperties": true, + "description": "One replacement in the draft: the span ``start``..``end`` of the\n``text`` you sent (Unicode code points, ``end`` exclusive, as in\n``Position``), ``text`` exactly that slice, and ``replacement`` what takes\nits place (``\"\"`` deletes it). ``position`` is the index of the claim\nrow's ``positions`` entry the edit sits in, for grouping by passage.\n\nCompare ``text`` with your draft before you apply an edit, so a draft that\nchanged since is never edited in the wrong place.", + "properties": { + "end": { + "default": 0, + "title": "End", + "type": "integer" + }, + "position": { + "default": 0, + "title": "Position", + "type": "integer" + }, + "replacement": { + "default": "", + "title": "Replacement", + "type": "string" + }, + "start": { + "default": 0, + "title": "Start", + "type": "integer" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "SuggestedEdit", + "type": "object" + }, + "SuggestedEdits": { + "additionalProperties": true, + "description": "The smallest edits to the draft that make it say what the claim's\n``suggested_rewrite`` says (the deep check's, or the quick check's on a\nclaim that stayed on the quick verdict), in the draft's own language\n(``review(..., suggest_edits=True)``).\n\n``status`` is ``\"pending\"`` while they are computed (``edits`` is\n``None``; keep polling) and ``\"completed\"`` once settled, which includes\nsettling on none (``edits == []``: no edit could be made safely, or it\ncould not be computed). They are not themselves verified:\nreview them before you publish.", + "properties": { + "edits": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/SuggestedEdit" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Edits" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "SuggestedEdits", + "type": "object" + } + }, + "additionalProperties": true, + "description": "What both views of ``GET /reviews/{review_id}`` carry.\n\n``status`` is the lifecycle: ``queued`` \u2192 ``assessing`` \u2192 ``verifying``\n\u2192 ``completed``, or ``failed``. ``outcome`` is ``None`` until the review\nends, then one of ``clean`` (every selected claim checked, no issue),\n``issues_found``, ``incomplete`` (some work failed) or ``unchecked`` (it\nfailed before any claim was checked; ``failure`` says why).\n\nOn a review that asked for the citation check, a citation issue makes\n``outcome`` ``issues_found`` too (``issues`` may then be empty: the rows\nare in ``citation_issues``), and a failed citation check makes it\n``incomplete``. ``status`` reads ``verifying`` while deep checks or\ncitation checks are running.\n\n``issues`` and ``failures`` can change until ``completed``.\n``poll_after_seconds`` is how long to wait before reading again; ``None``\nonce the review has ended.", + "properties": { + "citation_failures": { + "items": { + "$ref": "#/$defs/ReviewCitationFailure" + }, + "title": "Citation Failures", + "type": "array" + }, + "citation_issues": { + "items": { + "$ref": "#/$defs/ReviewCitationIssue" + }, + "title": "Citation Issues", + "type": "array" + }, + "completed_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Completed At" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "credits": { + "$ref": "#/$defs/ReviewCredits" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "failures": { + "items": { + "$ref": "#/$defs/ReviewFailure" + }, + "title": "Failures", + "type": "array" + }, + "issues": { + "items": { + "$ref": "#/$defs/ReviewIssue" + }, + "title": "Issues", + "type": "array" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "more_citations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ReviewMoreCitation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Citations" + }, + "more_claim_locations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ClaimLocation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claim Locations" + }, + "more_claims": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claims" + }, + "outcome": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Outcome" + }, + "policy": { + "$ref": "#/$defs/EscalationPolicy" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "review_id": { + "default": "", + "title": "Review Id", + "type": "string" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "summary": { + "$ref": "#/$defs/ReviewSummary" + }, + "view": { + "default": "", + "title": "View", + "type": "string" + } + }, + "title": "ReviewEnvelope", + "type": "object" + }, + "ReviewEnvelope:validation": { + "$defs": { + "ClaimLocation": { + "additionalProperties": true, + "description": "Where the submitted text makes one claim.\n\n``claim`` is exactly as in the claim list it belongs to\n(``ExtractedClaims.claim`` / ``identified_claims``, or a review's\n``more_claims``). ``positions`` lists every place the text makes it, in\ntext order, at most 10. It is ``None`` only when that claim could not be\nplaced; on ``/extract`` every returned claim is placed.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + } + }, + "title": "ClaimLocation", + "type": "object" + }, + "Escalation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "EscalationPolicy": { + "additionalProperties": true, + "description": "Which quick-checked claims get a deep check, as the review RESOLVED it.\n\nA claim is deep-checked when its quick verdict is in ``verdicts`` OR its\nconfidence band is in ``confidence``, up to ``max_verifications`` of them,\nat ``depth``. ``max_assessments`` is how many of the draft's claims, most\ncheck-worthy first, got a quick verdict.", + "properties": { + "confidence": { + "items": { + "type": "string" + }, + "title": "Confidence", + "type": "array" + }, + "depth": { + "default": "standard", + "title": "Depth", + "type": "string" + }, + "max_assessments": { + "default": 20, + "title": "Max Assessments", + "type": "integer" + }, + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + }, + "max_verifications": { + "default": 5, + "title": "Max Verifications", + "type": "integer" + }, + "suggest_edits": { + "default": false, + "title": "Suggest Edits", + "type": "boolean" + }, + "verdicts": { + "items": { + "type": "string" + }, + "title": "Verdicts", + "type": "array" + } + }, + "title": "EscalationPolicy", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewAssessmentCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + } + }, + "title": "ReviewAssessmentCounts", + "type": "object" + }, + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationFailure": { + "additionalProperties": true, + "description": "A citation whose check failed with nothing established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + } + }, + "title": "ReviewCitationFailure", + "type": "object" + }, + "ReviewCitationIssue": { + "additionalProperties": true, + "description": "A citation whose finding is an issue (see ``ReviewCitationResult``);\nmost serious first, then in the draft's order.\n\n``snippet`` and ``rationale`` are set only when ``source`` is\n``support``. On ``quote_not_in_source``, ``missing_quote`` is the quoted\nexcerpt that was not found. On ``metadata_mismatch``,\n``metadata_differences`` says what differs. ``failure`` is set when another part of the check failed after\nthe finding was established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitationIssue", + "type": "object" + }, + "ReviewCredits": { + "additionalProperties": true, + "description": "``charged`` is the net credits the review cost the account, its\ncitation checks included. It is final once no deep check or citation\ncheck is running: read it at ``completed``.", + "properties": { + "charged": { + "default": 0, + "title": "Charged", + "type": "integer" + } + }, + "title": "ReviewCredits", + "type": "object" + }, + "ReviewFailure": { + "additionalProperties": true, + "description": "A claim outside the issues whose work failed. ``stage`` is\n``assessment`` or ``verification``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "stage": { + "default": "", + "title": "Stage", + "type": "string" + } + }, + "title": "ReviewFailure", + "type": "object" + }, + "ReviewIssue": { + "additionalProperties": true, + "description": "A claim whose final verdict is ``False``, ``Mostly False`` or ``Mixed``.\n\n``source`` says which check the verdict comes from: ``verification`` (a\ndeep check, with ``verification_id``, ``url`` and ``key_finding``) or\n``assessment`` (the quick check only; ``escalation`` says why it was not\ndeep-checked, and ``rationale`` is the reviewers' note).\n``verified_claim`` is the deep check's wording of the claim when it\ndiffers from ``claim``. ``failure`` is set when the claim's deep check\nfailed.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_status": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Status" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "verified_claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verified Claim" + } + }, + "title": "ReviewIssue", + "type": "object" + }, + "ReviewMoreCitation": { + "additionalProperties": true, + "description": "A citation found in the draft past the ones this review checked:\nfound but not checked. Send it in a later request to check it.\n``sentence`` is the draft's sentence around it.", + "properties": { + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "sentence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Sentence" + } + }, + "title": "ReviewMoreCitation", + "type": "object" + }, + "ReviewSummary": { + "additionalProperties": true, + "description": "Counts over the review. A count is ``None`` until what it counts is\nknown (``claims_selected`` before the draft has been read).\n\nThe ``citation*`` counts are ``None`` (``citation_issues`` 0) on a review\nthat did not ask for the citation check.", + "properties": { + "assessments": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewAssessmentCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + }, + "citations_skipped": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Skipped" + }, + "claim_limit": { + "default": 20, + "title": "Claim Limit", + "type": "integer" + }, + "claim_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim Limit Reached" + }, + "claims_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claims Selected" + }, + "input_truncated": { + "default": false, + "title": "Input Truncated", + "type": "boolean" + }, + "issues": { + "default": 0, + "title": "Issues", + "type": "integer" + }, + "verifications": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerificationCounts" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewSummary", + "type": "object" + }, + "ReviewVerificationCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "planned": { + "default": 0, + "title": "Planned", + "type": "integer" + } + }, + "title": "ReviewVerificationCounts", + "type": "object" + }, + "SuggestedEdit": { + "additionalProperties": true, + "description": "One replacement in the draft: the span ``start``..``end`` of the\n``text`` you sent (Unicode code points, ``end`` exclusive, as in\n``Position``), ``text`` exactly that slice, and ``replacement`` what takes\nits place (``\"\"`` deletes it). ``position`` is the index of the claim\nrow's ``positions`` entry the edit sits in, for grouping by passage.\n\nCompare ``text`` with your draft before you apply an edit, so a draft that\nchanged since is never edited in the wrong place.", + "properties": { + "end": { + "default": 0, + "title": "End", + "type": "integer" + }, + "position": { + "default": 0, + "title": "Position", + "type": "integer" + }, + "replacement": { + "default": "", + "title": "Replacement", + "type": "string" + }, + "start": { + "default": 0, + "title": "Start", + "type": "integer" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "SuggestedEdit", + "type": "object" + }, + "SuggestedEdits": { + "additionalProperties": true, + "description": "The smallest edits to the draft that make it say what the claim's\n``suggested_rewrite`` says (the deep check's, or the quick check's on a\nclaim that stayed on the quick verdict), in the draft's own language\n(``review(..., suggest_edits=True)``).\n\n``status`` is ``\"pending\"`` while they are computed (``edits`` is\n``None``; keep polling) and ``\"completed\"`` once settled, which includes\nsettling on none (``edits == []``: no edit could be made safely, or it\ncould not be computed). They are not themselves verified:\nreview them before you publish.", + "properties": { + "edits": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/SuggestedEdit" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Edits" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "SuggestedEdits", + "type": "object" + } + }, + "additionalProperties": true, + "description": "What both views of ``GET /reviews/{review_id}`` carry.\n\n``status`` is the lifecycle: ``queued`` \u2192 ``assessing`` \u2192 ``verifying``\n\u2192 ``completed``, or ``failed``. ``outcome`` is ``None`` until the review\nends, then one of ``clean`` (every selected claim checked, no issue),\n``issues_found``, ``incomplete`` (some work failed) or ``unchecked`` (it\nfailed before any claim was checked; ``failure`` says why).\n\nOn a review that asked for the citation check, a citation issue makes\n``outcome`` ``issues_found`` too (``issues`` may then be empty: the rows\nare in ``citation_issues``), and a failed citation check makes it\n``incomplete``. ``status`` reads ``verifying`` while deep checks or\ncitation checks are running.\n\n``issues`` and ``failures`` can change until ``completed``.\n``poll_after_seconds`` is how long to wait before reading again; ``None``\nonce the review has ended.", + "properties": { + "citation_failures": { + "items": { + "$ref": "#/$defs/ReviewCitationFailure" + }, + "title": "Citation Failures", + "type": "array" + }, + "citation_issues": { + "items": { + "$ref": "#/$defs/ReviewCitationIssue" + }, + "title": "Citation Issues", + "type": "array" + }, + "completed_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Completed At" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "credits": { + "$ref": "#/$defs/ReviewCredits" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "failures": { + "items": { + "$ref": "#/$defs/ReviewFailure" + }, + "title": "Failures", + "type": "array" + }, + "issues": { + "items": { + "$ref": "#/$defs/ReviewIssue" + }, + "title": "Issues", + "type": "array" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "more_citations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ReviewMoreCitation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Citations" + }, + "more_claim_locations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ClaimLocation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claim Locations" + }, + "more_claims": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claims" + }, + "outcome": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Outcome" + }, + "policy": { + "$ref": "#/$defs/EscalationPolicy" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "review_id": { + "default": "", + "title": "Review Id", + "type": "string" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "summary": { + "$ref": "#/$defs/ReviewSummary" + }, + "view": { + "default": "", + "title": "View", + "type": "string" + } + }, + "title": "ReviewEnvelope", + "type": "object" + }, + "ReviewFailure:serialization": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A claim outside the issues whose work failed. ``stage`` is\n``assessment`` or ``verification``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "stage": { + "default": "", + "title": "Stage", + "type": "string" + } + }, + "title": "ReviewFailure", + "type": "object" + }, + "ReviewFailure:validation": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A claim outside the issues whose work failed. ``stage`` is\n``assessment`` or ``verification``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "stage": { + "default": "", + "title": "Stage", + "type": "string" + } + }, + "title": "ReviewFailure", + "type": "object" + }, + "ReviewFull:serialization": { + "$defs": { + "ClaimLocation": { + "additionalProperties": true, + "description": "Where the submitted text makes one claim.\n\n``claim`` is exactly as in the claim list it belongs to\n(``ExtractedClaims.claim`` / ``identified_claims``, or a review's\n``more_claims``). ``positions`` lists every place the text makes it, in\ntext order, at most 10. It is ``None`` only when that claim could not be\nplaced; on ``/extract`` every returned claim is placed.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + } + }, + "title": "ClaimLocation", + "type": "object" + }, + "Escalation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "EscalationPolicy": { + "additionalProperties": true, + "description": "Which quick-checked claims get a deep check, as the review RESOLVED it.\n\nA claim is deep-checked when its quick verdict is in ``verdicts`` OR its\nconfidence band is in ``confidence``, up to ``max_verifications`` of them,\nat ``depth``. ``max_assessments`` is how many of the draft's claims, most\ncheck-worthy first, got a quick verdict.", + "properties": { + "confidence": { + "items": { + "type": "string" + }, + "title": "Confidence", + "type": "array" + }, + "depth": { + "default": "standard", + "title": "Depth", + "type": "string" + }, + "max_assessments": { + "default": 20, + "title": "Max Assessments", + "type": "integer" + }, + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + }, + "max_verifications": { + "default": 5, + "title": "Max Verifications", + "type": "integer" + }, + "suggest_edits": { + "default": false, + "title": "Suggest Edits", + "type": "boolean" + }, + "verdicts": { + "items": { + "type": "string" + }, + "title": "Verdicts", + "type": "array" + } + }, + "title": "EscalationPolicy", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewAssessment": { + "additionalProperties": true, + "description": "A claim's quick check. ``status``: ``pending`` | ``running`` |\n``completed`` | ``failed``. On ``completed`` the fields mean what they\nmean on an ``/assess`` row; on ``failed`` see ``error_code`` (an open\nset, as on ``/assess``), ``hint`` and ``failure``.", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "dissent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dissent" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error Code" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + } + }, + "title": "ReviewAssessment", + "type": "object" + }, + "ReviewAssessmentCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + } + }, + "title": "ReviewAssessmentCounts", + "type": "object" + }, + "ReviewCitation": { + "additionalProperties": true, + "description": "One citation of the draft (a URL or a DOI where the draft uses it), in\nthe draft's order. Only on a review that asked for the citation check.\n\n``reference`` is the citation as the draft writes it; ``statement`` the\ndraft's sentence it is attached to, with link syntax reduced to its\nwords; ``quotes`` the words the draft quotes from this source.\n``position`` locates ``statement`` in the text as sent (its ``text`` is\n``None``: the row carries the ``statement``). ``result`` is\n``None`` until the check has ended, and on a failed row with nothing\nestablished.", + "properties": { + "check": { + "$ref": "#/$defs/ReviewCitationCheck" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationResult" + }, + { + "type": "null" + } + ], + "default": null + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitation", + "type": "object" + }, + "ReviewCitationCheck": { + "additionalProperties": true, + "description": "A citation's check. ``status`` is progress, as on ``assessment``:\n``pending`` | ``running`` | ``completed`` | ``failed``.\n\n- ``page_read``: ``full``, ``partial``, ``not_found`` or ``none``.\n- ``source_url``: where the text was actually read from (after\n redirects, or a free copy of a paper). ``source_version``, for a DOI:\n ``published``, ``accepted`` or ``submitted``.\n- ``support``: ``supported``, ``partly_supported``, ``contradicted``,\n ``not_in_source`` or ``unchecked``. ``snippet`` is the verified passage\n of the source it rests on; ``rationale`` is a reviewer's note, not a\n checked source.\n- ``quote``: ``matched``, ``not_in_source`` or ``unchecked``; ``None``\n when the draft quoted nothing from this source. ``missing_quote`` is\n the quoted excerpt the quote check did not find; ``None`` unless\n ``quote`` is ``not_in_source``.\n- ``doi_registered``, ``metadata`` (``consistent``, ``mismatch`` or\n ``unchecked``), ``metadata_differences`` and ``registered``: set for a\n DOI only.\n- ``unchecked_reason`` and ``hint``: why the finding is ``unchecked`` and\n what to do next. The reasons are an open set, e.g. ``no_text``,\n ``partial_text``, ``login_required``, ``unsupported_site``,\n ``no_statement``, ``invalid_url``, ``other_version``, ``inconclusive``,\n ``ambiguous_reference``.\n- ``failure``: on a ``failed`` check.", + "properties": { + "doi_registered": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi Registered" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "metadata": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Metadata" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Language" + }, + "page_published_date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Published Date" + }, + "page_read": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Read" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Quote" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "registered": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationRecord" + }, + { + "type": "null" + } + ], + "default": null + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Url" + }, + "source_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Version" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "support": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Support" + }, + "unchecked_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Unchecked Reason" + } + }, + "title": "ReviewCitationCheck", + "type": "object" + }, + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationFailure": { + "additionalProperties": true, + "description": "A citation whose check failed with nothing established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + } + }, + "title": "ReviewCitationFailure", + "type": "object" + }, + "ReviewCitationIssue": { + "additionalProperties": true, + "description": "A citation whose finding is an issue (see ``ReviewCitationResult``);\nmost serious first, then in the draft's order.\n\n``snippet`` and ``rationale`` are set only when ``source`` is\n``support``. On ``quote_not_in_source``, ``missing_quote`` is the quoted\nexcerpt that was not found. On ``metadata_mismatch``,\n``metadata_differences`` says what differs. ``failure`` is set when another part of the check failed after\nthe finding was established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitationIssue", + "type": "object" + }, + "ReviewCitationRecord": { + "additionalProperties": true, + "description": "A DOI's record in the registry.", + "properties": { + "authors": { + "items": { + "type": "string" + }, + "title": "Authors", + "type": "array" + }, + "journal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Journal" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "year": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Year" + } + }, + "title": "ReviewCitationRecord", + "type": "object" + }, + "ReviewCitationResult": { + "additionalProperties": true, + "description": "The one answer to read for a citation, derived from its ``check``.\n\n``finding``, most serious first: ``doi_not_found``, ``page_not_found``,\n``contradicted``, ``quote_not_in_source``, ``not_in_source``,\n``partly_supported``, ``metadata_mismatch`` (each an issue), then\n``supported`` and ``unchecked``. ``source`` says which check the finding\ncame from: ``doi``, ``page``, ``support``, ``quote`` or ``metadata``;\n``None`` on ``unchecked``.", + "properties": { + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + } + }, + "title": "ReviewCitationResult", + "type": "object" + }, + "ReviewClaim": { + "additionalProperties": true, + "description": "One claim of the draft, in the order the draft's claims were read.\n\n``result`` is ``None`` until the quick check completes, and on a failed\none. ``escalation`` is ``None`` until then too. ``verification`` is set\nonce a deep check was planned for the claim.\n\n``positions`` lists every place the draft makes the claim, in text\norder, at most 10 (see ``Position``). ``start`` / ``end`` index the\n``text`` you sent in Unicode code points (``text[start:end]`` in Python;\n``end`` exclusive), the same coordinates as a citation's ``position``.\nFor a URL draft, ``start`` and ``end`` are ``None`` and ``text`` carries\nthe passage. ``positions`` is ``None`` when the claims could not be\nlocated, or once a zero-retention draft is gone (and from servers that\npredate the field).", + "properties": { + "assessment": { + "$ref": "#/$defs/ReviewAssessment" + }, + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewResult" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "verification": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerification" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewClaim", + "type": "object" + }, + "ReviewCredits": { + "additionalProperties": true, + "description": "``charged`` is the net credits the review cost the account, its\ncitation checks included. It is final once no deep check or citation\ncheck is running: read it at ``completed``.", + "properties": { + "charged": { + "default": 0, + "title": "Charged", + "type": "integer" + } + }, + "title": "ReviewCredits", + "type": "object" + }, + "ReviewEntity": { + "additionalProperties": true, + "description": "An entity the deep check found in the claim. ``qid`` is its Wikidata\nid when resolved. Either may be ``None``.", + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "ReviewEntity", + "type": "object" + }, + "ReviewFailure": { + "additionalProperties": true, + "description": "A claim outside the issues whose work failed. ``stage`` is\n``assessment`` or ``verification``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "stage": { + "default": "", + "title": "Stage", + "type": "string" + } + }, + "title": "ReviewFailure", + "type": "object" + }, + "ReviewIssue": { + "additionalProperties": true, + "description": "A claim whose final verdict is ``False``, ``Mostly False`` or ``Mixed``.\n\n``source`` says which check the verdict comes from: ``verification`` (a\ndeep check, with ``verification_id``, ``url`` and ``key_finding``) or\n``assessment`` (the quick check only; ``escalation`` says why it was not\ndeep-checked, and ``rationale`` is the reviewers' note).\n``verified_claim`` is the deep check's wording of the claim when it\ndiffers from ``claim``. ``failure`` is set when the claim's deep check\nfailed.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_status": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Status" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "verified_claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verified Claim" + } + }, + "title": "ReviewIssue", + "type": "object" + }, + "ReviewMoreCitation": { + "additionalProperties": true, + "description": "A citation found in the draft past the ones this review checked:\nfound but not checked. Send it in a later request to check it.\n``sentence`` is the draft's sentence around it.", + "properties": { + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "sentence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Sentence" + } + }, + "title": "ReviewMoreCitation", + "type": "object" + }, + "ReviewResult": { + "additionalProperties": true, + "description": "The one answer to read for a claim: the deep check's verdict when it\ncompleted, else the quick check's. ``source`` says which\n(``assessment`` or ``verification``).", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + } + }, + "title": "ReviewResult", + "type": "object" + }, + "ReviewSummary": { + "additionalProperties": true, + "description": "Counts over the review. A count is ``None`` until what it counts is\nknown (``claims_selected`` before the draft has been read).\n\nThe ``citation*`` counts are ``None`` (``citation_issues`` 0) on a review\nthat did not ask for the citation check.", + "properties": { + "assessments": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewAssessmentCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + }, + "citations_skipped": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Skipped" + }, + "claim_limit": { + "default": 20, + "title": "Claim Limit", + "type": "integer" + }, + "claim_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim Limit Reached" + }, + "claims_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claims Selected" + }, + "input_truncated": { + "default": false, + "title": "Input Truncated", + "type": "boolean" + }, + "issues": { + "default": 0, + "title": "Issues", + "type": "integer" + }, + "verifications": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerificationCounts" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewSummary", + "type": "object" + }, + "ReviewVerification": { + "additionalProperties": true, + "description": "A claim's deep check. ``status``: ``processing`` | ``completed`` |\n``failed``; while ``processing`` only ``status``, ``content_status`` and\nthe ids are set. ``content_status`` is ``purged`` once the verification\nwas deleted or removed by its account's retention period: the verdict and\nids stay, the text fields and links are ``None``.\n\n``visibility`` and ``depth`` are what the verification actually has: a\nverdict served from an earlier check keeps its own visibility and may be\n``standard`` for a ``low`` request. Sources are on the verification\nitself: ``client.verifications.get(verification_id)``, or ``url``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "content_status": { + "default": "available", + "title": "Content Status", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Depth" + }, + "domain": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Domain" + }, + "entities": { + "items": { + "$ref": "#/$defs/ReviewEntity" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Executive Summary" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Language" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "task_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Task Id" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "visibility": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Visibility" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "ReviewVerification", + "type": "object" + }, + "ReviewVerificationCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "planned": { + "default": 0, + "title": "Planned", + "type": "integer" + } + }, + "title": "ReviewVerificationCounts", + "type": "object" + }, + "SuggestedEdit": { + "additionalProperties": true, + "description": "One replacement in the draft: the span ``start``..``end`` of the\n``text`` you sent (Unicode code points, ``end`` exclusive, as in\n``Position``), ``text`` exactly that slice, and ``replacement`` what takes\nits place (``\"\"`` deletes it). ``position`` is the index of the claim\nrow's ``positions`` entry the edit sits in, for grouping by passage.\n\nCompare ``text`` with your draft before you apply an edit, so a draft that\nchanged since is never edited in the wrong place.", + "properties": { + "end": { + "default": 0, + "title": "End", + "type": "integer" + }, + "position": { + "default": 0, + "title": "Position", + "type": "integer" + }, + "replacement": { + "default": "", + "title": "Replacement", + "type": "string" + }, + "start": { + "default": 0, + "title": "Start", + "type": "integer" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "SuggestedEdit", + "type": "object" + }, + "SuggestedEdits": { + "additionalProperties": true, + "description": "The smallest edits to the draft that make it say what the claim's\n``suggested_rewrite`` says (the deep check's, or the quick check's on a\nclaim that stayed on the quick verdict), in the draft's own language\n(``review(..., suggest_edits=True)``).\n\n``status`` is ``\"pending\"`` while they are computed (``edits`` is\n``None``; keep polling) and ``\"completed\"`` once settled, which includes\nsettling on none (``edits == []``: no edit could be made safely, or it\ncould not be computed). They are not themselves verified:\nreview them before you publish.", + "properties": { + "edits": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/SuggestedEdit" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Edits" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "SuggestedEdits", + "type": "object" + } + }, + "additionalProperties": true, + "description": "``GET /reviews/{review_id}``: the envelope plus every claim.", + "properties": { + "citation_failures": { + "items": { + "$ref": "#/$defs/ReviewCitationFailure" + }, + "title": "Citation Failures", + "type": "array" + }, + "citation_issues": { + "items": { + "$ref": "#/$defs/ReviewCitationIssue" + }, + "title": "Citation Issues", + "type": "array" + }, + "citations": { + "items": { + "$ref": "#/$defs/ReviewCitation" + }, + "title": "Citations", + "type": "array" + }, + "claims": { + "items": { + "$ref": "#/$defs/ReviewClaim" + }, + "title": "Claims", + "type": "array" + }, + "completed_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Completed At" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "credits": { + "$ref": "#/$defs/ReviewCredits" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "failures": { + "items": { + "$ref": "#/$defs/ReviewFailure" + }, + "title": "Failures", + "type": "array" + }, + "issues": { + "items": { + "$ref": "#/$defs/ReviewIssue" + }, + "title": "Issues", + "type": "array" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "more_citations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ReviewMoreCitation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Citations" + }, + "more_claim_locations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ClaimLocation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claim Locations" + }, + "more_claims": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claims" + }, + "outcome": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Outcome" + }, + "policy": { + "$ref": "#/$defs/EscalationPolicy" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "review_id": { + "default": "", + "title": "Review Id", + "type": "string" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "summary": { + "$ref": "#/$defs/ReviewSummary" + }, + "view": { + "default": "full", + "title": "View", + "type": "string" + } + }, + "title": "ReviewFull", + "type": "object" + }, + "ReviewFull:validation": { + "$defs": { + "ClaimLocation": { + "additionalProperties": true, + "description": "Where the submitted text makes one claim.\n\n``claim`` is exactly as in the claim list it belongs to\n(``ExtractedClaims.claim`` / ``identified_claims``, or a review's\n``more_claims``). ``positions`` lists every place the text makes it, in\ntext order, at most 10. It is ``None`` only when that claim could not be\nplaced; on ``/extract`` every returned claim is placed.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + } + }, + "title": "ClaimLocation", + "type": "object" + }, + "Escalation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "EscalationPolicy": { + "additionalProperties": true, + "description": "Which quick-checked claims get a deep check, as the review RESOLVED it.\n\nA claim is deep-checked when its quick verdict is in ``verdicts`` OR its\nconfidence band is in ``confidence``, up to ``max_verifications`` of them,\nat ``depth``. ``max_assessments`` is how many of the draft's claims, most\ncheck-worthy first, got a quick verdict.", + "properties": { + "confidence": { + "items": { + "type": "string" + }, + "title": "Confidence", + "type": "array" + }, + "depth": { + "default": "standard", + "title": "Depth", + "type": "string" + }, + "max_assessments": { + "default": 20, + "title": "Max Assessments", + "type": "integer" + }, + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + }, + "max_verifications": { + "default": 5, + "title": "Max Verifications", + "type": "integer" + }, + "suggest_edits": { + "default": false, + "title": "Suggest Edits", + "type": "boolean" + }, + "verdicts": { + "items": { + "type": "string" + }, + "title": "Verdicts", + "type": "array" + } + }, + "title": "EscalationPolicy", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewAssessment": { + "additionalProperties": true, + "description": "A claim's quick check. ``status``: ``pending`` | ``running`` |\n``completed`` | ``failed``. On ``completed`` the fields mean what they\nmean on an ``/assess`` row; on ``failed`` see ``error_code`` (an open\nset, as on ``/assess``), ``hint`` and ``failure``.", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "dissent": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Dissent" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Error Code" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "identified_claims": { + "items": { + "type": "string" + }, + "title": "Identified Claims", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + } + }, + "title": "ReviewAssessment", + "type": "object" + }, + "ReviewAssessmentCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + } + }, + "title": "ReviewAssessmentCounts", + "type": "object" + }, + "ReviewCitation": { + "additionalProperties": true, + "description": "One citation of the draft (a URL or a DOI where the draft uses it), in\nthe draft's order. Only on a review that asked for the citation check.\n\n``reference`` is the citation as the draft writes it; ``statement`` the\ndraft's sentence it is attached to, with link syntax reduced to its\nwords; ``quotes`` the words the draft quotes from this source.\n``position`` locates ``statement`` in the text as sent (its ``text`` is\n``None``: the row carries the ``statement``). ``result`` is\n``None`` until the check has ended, and on a failed row with nothing\nestablished.", + "properties": { + "check": { + "$ref": "#/$defs/ReviewCitationCheck" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationResult" + }, + { + "type": "null" + } + ], + "default": null + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitation", + "type": "object" + }, + "ReviewCitationCheck": { + "additionalProperties": true, + "description": "A citation's check. ``status`` is progress, as on ``assessment``:\n``pending`` | ``running`` | ``completed`` | ``failed``.\n\n- ``page_read``: ``full``, ``partial``, ``not_found`` or ``none``.\n- ``source_url``: where the text was actually read from (after\n redirects, or a free copy of a paper). ``source_version``, for a DOI:\n ``published``, ``accepted`` or ``submitted``.\n- ``support``: ``supported``, ``partly_supported``, ``contradicted``,\n ``not_in_source`` or ``unchecked``. ``snippet`` is the verified passage\n of the source it rests on; ``rationale`` is a reviewer's note, not a\n checked source.\n- ``quote``: ``matched``, ``not_in_source`` or ``unchecked``; ``None``\n when the draft quoted nothing from this source. ``missing_quote`` is\n the quoted excerpt the quote check did not find; ``None`` unless\n ``quote`` is ``not_in_source``.\n- ``doi_registered``, ``metadata`` (``consistent``, ``mismatch`` or\n ``unchecked``), ``metadata_differences`` and ``registered``: set for a\n DOI only.\n- ``unchecked_reason`` and ``hint``: why the finding is ``unchecked`` and\n what to do next. The reasons are an open set, e.g. ``no_text``,\n ``partial_text``, ``login_required``, ``unsupported_site``,\n ``no_statement``, ``invalid_url``, ``other_version``, ``inconclusive``,\n ``ambiguous_reference``.\n- ``failure``: on a ``failed`` check.", + "properties": { + "doi_registered": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi Registered" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "metadata": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Metadata" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Language" + }, + "page_published_date": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Published Date" + }, + "page_read": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Read" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Quote" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "registered": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationRecord" + }, + { + "type": "null" + } + ], + "default": null + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Url" + }, + "source_version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source Version" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "support": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Support" + }, + "unchecked_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Unchecked Reason" + } + }, + "title": "ReviewCitationCheck", + "type": "object" + }, + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationFailure": { + "additionalProperties": true, + "description": "A citation whose check failed with nothing established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + } + }, + "title": "ReviewCitationFailure", + "type": "object" + }, + "ReviewCitationIssue": { + "additionalProperties": true, + "description": "A citation whose finding is an issue (see ``ReviewCitationResult``);\nmost serious first, then in the draft's order.\n\n``snippet`` and ``rationale`` are set only when ``source`` is\n``support``. On ``quote_not_in_source``, ``missing_quote`` is the quoted\nexcerpt that was not found. On ``metadata_mismatch``,\n``metadata_differences`` says what differs. ``failure`` is set when another part of the check failed after\nthe finding was established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitationIssue", + "type": "object" + }, + "ReviewCitationRecord": { + "additionalProperties": true, + "description": "A DOI's record in the registry.", + "properties": { + "authors": { + "items": { + "type": "string" + }, + "title": "Authors", + "type": "array" + }, + "journal": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Journal" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Title" + }, + "year": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Year" + } + }, + "title": "ReviewCitationRecord", + "type": "object" + }, + "ReviewCitationResult": { + "additionalProperties": true, + "description": "The one answer to read for a citation, derived from its ``check``.\n\n``finding``, most serious first: ``doi_not_found``, ``page_not_found``,\n``contradicted``, ``quote_not_in_source``, ``not_in_source``,\n``partly_supported``, ``metadata_mismatch`` (each an issue), then\n``supported`` and ``unchecked``. ``source`` says which check the finding\ncame from: ``doi``, ``page``, ``support``, ``quote`` or ``metadata``;\n``None`` on ``unchecked``.", + "properties": { + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + } + }, + "title": "ReviewCitationResult", + "type": "object" + }, + "ReviewClaim": { + "additionalProperties": true, + "description": "One claim of the draft, in the order the draft's claims were read.\n\n``result`` is ``None`` until the quick check completes, and on a failed\none. ``escalation`` is ``None`` until then too. ``verification`` is set\nonce a deep check was planned for the claim.\n\n``positions`` lists every place the draft makes the claim, in text\norder, at most 10 (see ``Position``). ``start`` / ``end`` index the\n``text`` you sent in Unicode code points (``text[start:end]`` in Python;\n``end`` exclusive), the same coordinates as a citation's ``position``.\nFor a URL draft, ``start`` and ``end`` are ``None`` and ``text`` carries\nthe passage. ``positions`` is ``None`` when the claims could not be\nlocated, or once a zero-retention draft is gone (and from servers that\npredate the field).", + "properties": { + "assessment": { + "$ref": "#/$defs/ReviewAssessment" + }, + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewResult" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "verification": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerification" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewClaim", + "type": "object" + }, + "ReviewCredits": { + "additionalProperties": true, + "description": "``charged`` is the net credits the review cost the account, its\ncitation checks included. It is final once no deep check or citation\ncheck is running: read it at ``completed``.", + "properties": { + "charged": { + "default": 0, + "title": "Charged", + "type": "integer" + } + }, + "title": "ReviewCredits", + "type": "object" + }, + "ReviewEntity": { + "additionalProperties": true, + "description": "An entity the deep check found in the claim. ``qid`` is its Wikidata\nid when resolved. Either may be ``None``.", + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "ReviewEntity", + "type": "object" + }, + "ReviewFailure": { + "additionalProperties": true, + "description": "A claim outside the issues whose work failed. ``stage`` is\n``assessment`` or ``verification``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "stage": { + "default": "", + "title": "Stage", + "type": "string" + } + }, + "title": "ReviewFailure", + "type": "object" + }, + "ReviewIssue": { + "additionalProperties": true, + "description": "A claim whose final verdict is ``False``, ``Mostly False`` or ``Mixed``.\n\n``source`` says which check the verdict comes from: ``verification`` (a\ndeep check, with ``verification_id``, ``url`` and ``key_finding``) or\n``assessment`` (the quick check only; ``escalation`` says why it was not\ndeep-checked, and ``rationale`` is the reviewers' note).\n``verified_claim`` is the deep check's wording of the claim when it\ndiffers from ``claim``. ``failure`` is set when the claim's deep check\nfailed.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_status": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Status" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "verified_claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verified Claim" + } + }, + "title": "ReviewIssue", + "type": "object" + }, + "ReviewMoreCitation": { + "additionalProperties": true, + "description": "A citation found in the draft past the ones this review checked:\nfound but not checked. Send it in a later request to check it.\n``sentence`` is the draft's sentence around it.", + "properties": { + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "sentence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Sentence" + } + }, + "title": "ReviewMoreCitation", + "type": "object" + }, + "ReviewResult": { + "additionalProperties": true, + "description": "The one answer to read for a claim: the deep check's verdict when it\ncompleted, else the quick check's. ``source`` says which\n(``assessment`` or ``verification``).", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + } + }, + "title": "ReviewResult", + "type": "object" + }, + "ReviewSummary": { + "additionalProperties": true, + "description": "Counts over the review. A count is ``None`` until what it counts is\nknown (``claims_selected`` before the draft has been read).\n\nThe ``citation*`` counts are ``None`` (``citation_issues`` 0) on a review\nthat did not ask for the citation check.", + "properties": { + "assessments": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewAssessmentCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + }, + "citations_skipped": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Skipped" + }, + "claim_limit": { + "default": 20, + "title": "Claim Limit", + "type": "integer" + }, + "claim_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim Limit Reached" + }, + "claims_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claims Selected" + }, + "input_truncated": { + "default": false, + "title": "Input Truncated", + "type": "boolean" + }, + "issues": { + "default": 0, + "title": "Issues", + "type": "integer" + }, + "verifications": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerificationCounts" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewSummary", + "type": "object" + }, + "ReviewVerification": { + "additionalProperties": true, + "description": "A claim's deep check. ``status``: ``processing`` | ``completed`` |\n``failed``; while ``processing`` only ``status``, ``content_status`` and\nthe ids are set. ``content_status`` is ``purged`` once the verification\nwas deleted or removed by its account's retention period: the verdict and\nids stay, the text fields and links are ``None``.\n\n``visibility`` and ``depth`` are what the verification actually has: a\nverdict served from an earlier check keeps its own visibility and may be\n``standard`` for a ``low`` request. Sources are on the verification\nitself: ``client.verifications.get(verification_id)``, or ``url``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "content_status": { + "default": "available", + "title": "Content Status", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Depth" + }, + "domain": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Domain" + }, + "entities": { + "items": { + "$ref": "#/$defs/ReviewEntity" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Executive Summary" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Language" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "task_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Task Id" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "visibility": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Visibility" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "ReviewVerification", + "type": "object" + }, + "ReviewVerificationCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "planned": { + "default": 0, + "title": "Planned", + "type": "integer" + } + }, + "title": "ReviewVerificationCounts", + "type": "object" + }, + "SuggestedEdit": { + "additionalProperties": true, + "description": "One replacement in the draft: the span ``start``..``end`` of the\n``text`` you sent (Unicode code points, ``end`` exclusive, as in\n``Position``), ``text`` exactly that slice, and ``replacement`` what takes\nits place (``\"\"`` deletes it). ``position`` is the index of the claim\nrow's ``positions`` entry the edit sits in, for grouping by passage.\n\nCompare ``text`` with your draft before you apply an edit, so a draft that\nchanged since is never edited in the wrong place.", + "properties": { + "end": { + "default": 0, + "title": "End", + "type": "integer" + }, + "position": { + "default": 0, + "title": "Position", + "type": "integer" + }, + "replacement": { + "default": "", + "title": "Replacement", + "type": "string" + }, + "start": { + "default": 0, + "title": "Start", + "type": "integer" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "SuggestedEdit", + "type": "object" + }, + "SuggestedEdits": { + "additionalProperties": true, + "description": "The smallest edits to the draft that make it say what the claim's\n``suggested_rewrite`` says (the deep check's, or the quick check's on a\nclaim that stayed on the quick verdict), in the draft's own language\n(``review(..., suggest_edits=True)``).\n\n``status`` is ``\"pending\"`` while they are computed (``edits`` is\n``None``; keep polling) and ``\"completed\"`` once settled, which includes\nsettling on none (``edits == []``: no edit could be made safely, or it\ncould not be computed). They are not themselves verified:\nreview them before you publish.", + "properties": { + "edits": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/SuggestedEdit" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Edits" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "SuggestedEdits", + "type": "object" + } + }, + "additionalProperties": true, + "description": "``GET /reviews/{review_id}``: the envelope plus every claim.", + "properties": { + "citation_failures": { + "items": { + "$ref": "#/$defs/ReviewCitationFailure" + }, + "title": "Citation Failures", + "type": "array" + }, + "citation_issues": { + "items": { + "$ref": "#/$defs/ReviewCitationIssue" + }, + "title": "Citation Issues", + "type": "array" + }, + "citations": { + "items": { + "$ref": "#/$defs/ReviewCitation" + }, + "title": "Citations", + "type": "array" + }, + "claims": { + "items": { + "$ref": "#/$defs/ReviewClaim" + }, + "title": "Claims", + "type": "array" + }, + "completed_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Completed At" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "credits": { + "$ref": "#/$defs/ReviewCredits" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "failures": { + "items": { + "$ref": "#/$defs/ReviewFailure" + }, + "title": "Failures", + "type": "array" + }, + "issues": { + "items": { + "$ref": "#/$defs/ReviewIssue" + }, + "title": "Issues", + "type": "array" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "more_citations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ReviewMoreCitation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Citations" + }, + "more_claim_locations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ClaimLocation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claim Locations" + }, + "more_claims": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claims" + }, + "outcome": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Outcome" + }, + "policy": { + "$ref": "#/$defs/EscalationPolicy" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "review_id": { + "default": "", + "title": "Review Id", + "type": "string" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "summary": { + "$ref": "#/$defs/ReviewSummary" + }, + "view": { + "default": "full", + "title": "View", + "type": "string" + } + }, + "title": "ReviewFull", + "type": "object" + }, + "ReviewIssue:serialization": { + "$defs": { + "Escalation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "SuggestedEdit": { + "additionalProperties": true, + "description": "One replacement in the draft: the span ``start``..``end`` of the\n``text`` you sent (Unicode code points, ``end`` exclusive, as in\n``Position``), ``text`` exactly that slice, and ``replacement`` what takes\nits place (``\"\"`` deletes it). ``position`` is the index of the claim\nrow's ``positions`` entry the edit sits in, for grouping by passage.\n\nCompare ``text`` with your draft before you apply an edit, so a draft that\nchanged since is never edited in the wrong place.", + "properties": { + "end": { + "default": 0, + "title": "End", + "type": "integer" + }, + "position": { + "default": 0, + "title": "Position", + "type": "integer" + }, + "replacement": { + "default": "", + "title": "Replacement", + "type": "string" + }, + "start": { + "default": 0, + "title": "Start", + "type": "integer" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "SuggestedEdit", + "type": "object" + }, + "SuggestedEdits": { + "additionalProperties": true, + "description": "The smallest edits to the draft that make it say what the claim's\n``suggested_rewrite`` says (the deep check's, or the quick check's on a\nclaim that stayed on the quick verdict), in the draft's own language\n(``review(..., suggest_edits=True)``).\n\n``status`` is ``\"pending\"`` while they are computed (``edits`` is\n``None``; keep polling) and ``\"completed\"`` once settled, which includes\nsettling on none (``edits == []``: no edit could be made safely, or it\ncould not be computed). They are not themselves verified:\nreview them before you publish.", + "properties": { + "edits": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/SuggestedEdit" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Edits" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "SuggestedEdits", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A claim whose final verdict is ``False``, ``Mostly False`` or ``Mixed``.\n\n``source`` says which check the verdict comes from: ``verification`` (a\ndeep check, with ``verification_id``, ``url`` and ``key_finding``) or\n``assessment`` (the quick check only; ``escalation`` says why it was not\ndeep-checked, and ``rationale`` is the reviewers' note).\n``verified_claim`` is the deep check's wording of the claim when it\ndiffers from ``claim``. ``failure`` is set when the claim's deep check\nfailed.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_status": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Status" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "verified_claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verified Claim" + } + }, + "title": "ReviewIssue", + "type": "object" + }, + "ReviewIssue:validation": { + "$defs": { + "Escalation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "SuggestedEdit": { + "additionalProperties": true, + "description": "One replacement in the draft: the span ``start``..``end`` of the\n``text`` you sent (Unicode code points, ``end`` exclusive, as in\n``Position``), ``text`` exactly that slice, and ``replacement`` what takes\nits place (``\"\"`` deletes it). ``position`` is the index of the claim\nrow's ``positions`` entry the edit sits in, for grouping by passage.\n\nCompare ``text`` with your draft before you apply an edit, so a draft that\nchanged since is never edited in the wrong place.", + "properties": { + "end": { + "default": 0, + "title": "End", + "type": "integer" + }, + "position": { + "default": 0, + "title": "Position", + "type": "integer" + }, + "replacement": { + "default": "", + "title": "Replacement", + "type": "string" + }, + "start": { + "default": 0, + "title": "Start", + "type": "integer" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "SuggestedEdit", + "type": "object" + }, + "SuggestedEdits": { + "additionalProperties": true, + "description": "The smallest edits to the draft that make it say what the claim's\n``suggested_rewrite`` says (the deep check's, or the quick check's on a\nclaim that stayed on the quick verdict), in the draft's own language\n(``review(..., suggest_edits=True)``).\n\n``status`` is ``\"pending\"`` while they are computed (``edits`` is\n``None``; keep polling) and ``\"completed\"`` once settled, which includes\nsettling on none (``edits == []``: no edit could be made safely, or it\ncould not be computed). They are not themselves verified:\nreview them before you publish.", + "properties": { + "edits": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/SuggestedEdit" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Edits" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "SuggestedEdits", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A claim whose final verdict is ``False``, ``Mostly False`` or ``Mixed``.\n\n``source`` says which check the verdict comes from: ``verification`` (a\ndeep check, with ``verification_id``, ``url`` and ``key_finding``) or\n``assessment`` (the quick check only; ``escalation`` says why it was not\ndeep-checked, and ``rationale`` is the reviewers' note).\n``verified_claim`` is the deep check's wording of the claim when it\ndiffers from ``claim``. ``failure`` is set when the claim's deep check\nfailed.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_status": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Status" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "verified_claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verified Claim" + } + }, + "title": "ReviewIssue", + "type": "object" + }, + "ReviewIssues:serialization": { + "$defs": { + "ClaimLocation": { + "additionalProperties": true, + "description": "Where the submitted text makes one claim.\n\n``claim`` is exactly as in the claim list it belongs to\n(``ExtractedClaims.claim`` / ``identified_claims``, or a review's\n``more_claims``). ``positions`` lists every place the text makes it, in\ntext order, at most 10. It is ``None`` only when that claim could not be\nplaced; on ``/extract`` every returned claim is placed.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + } + }, + "title": "ClaimLocation", + "type": "object" + }, + "Escalation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "EscalationPolicy": { + "additionalProperties": true, + "description": "Which quick-checked claims get a deep check, as the review RESOLVED it.\n\nA claim is deep-checked when its quick verdict is in ``verdicts`` OR its\nconfidence band is in ``confidence``, up to ``max_verifications`` of them,\nat ``depth``. ``max_assessments`` is how many of the draft's claims, most\ncheck-worthy first, got a quick verdict.", + "properties": { + "confidence": { + "items": { + "type": "string" + }, + "title": "Confidence", + "type": "array" + }, + "depth": { + "default": "standard", + "title": "Depth", + "type": "string" + }, + "max_assessments": { + "default": 20, + "title": "Max Assessments", + "type": "integer" + }, + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + }, + "max_verifications": { + "default": 5, + "title": "Max Verifications", + "type": "integer" + }, + "suggest_edits": { + "default": false, + "title": "Suggest Edits", + "type": "boolean" + }, + "verdicts": { + "items": { + "type": "string" + }, + "title": "Verdicts", + "type": "array" + } + }, + "title": "EscalationPolicy", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewAssessmentCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + } + }, + "title": "ReviewAssessmentCounts", + "type": "object" + }, + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationFailure": { + "additionalProperties": true, + "description": "A citation whose check failed with nothing established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + } + }, + "title": "ReviewCitationFailure", + "type": "object" + }, + "ReviewCitationIssue": { + "additionalProperties": true, + "description": "A citation whose finding is an issue (see ``ReviewCitationResult``);\nmost serious first, then in the draft's order.\n\n``snippet`` and ``rationale`` are set only when ``source`` is\n``support``. On ``quote_not_in_source``, ``missing_quote`` is the quoted\nexcerpt that was not found. On ``metadata_mismatch``,\n``metadata_differences`` says what differs. ``failure`` is set when another part of the check failed after\nthe finding was established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitationIssue", + "type": "object" + }, + "ReviewCredits": { + "additionalProperties": true, + "description": "``charged`` is the net credits the review cost the account, its\ncitation checks included. It is final once no deep check or citation\ncheck is running: read it at ``completed``.", + "properties": { + "charged": { + "default": 0, + "title": "Charged", + "type": "integer" + } + }, + "title": "ReviewCredits", + "type": "object" + }, + "ReviewFailure": { + "additionalProperties": true, + "description": "A claim outside the issues whose work failed. ``stage`` is\n``assessment`` or ``verification``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "stage": { + "default": "", + "title": "Stage", + "type": "string" + } + }, + "title": "ReviewFailure", + "type": "object" + }, + "ReviewIssue": { + "additionalProperties": true, + "description": "A claim whose final verdict is ``False``, ``Mostly False`` or ``Mixed``.\n\n``source`` says which check the verdict comes from: ``verification`` (a\ndeep check, with ``verification_id``, ``url`` and ``key_finding``) or\n``assessment`` (the quick check only; ``escalation`` says why it was not\ndeep-checked, and ``rationale`` is the reviewers' note).\n``verified_claim`` is the deep check's wording of the claim when it\ndiffers from ``claim``. ``failure`` is set when the claim's deep check\nfailed.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_status": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Status" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "verified_claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verified Claim" + } + }, + "title": "ReviewIssue", + "type": "object" + }, + "ReviewMoreCitation": { + "additionalProperties": true, + "description": "A citation found in the draft past the ones this review checked:\nfound but not checked. Send it in a later request to check it.\n``sentence`` is the draft's sentence around it.", + "properties": { + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "sentence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Sentence" + } + }, + "title": "ReviewMoreCitation", + "type": "object" + }, + "ReviewSummary": { + "additionalProperties": true, + "description": "Counts over the review. A count is ``None`` until what it counts is\nknown (``claims_selected`` before the draft has been read).\n\nThe ``citation*`` counts are ``None`` (``citation_issues`` 0) on a review\nthat did not ask for the citation check.", + "properties": { + "assessments": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewAssessmentCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + }, + "citations_skipped": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Skipped" + }, + "claim_limit": { + "default": 20, + "title": "Claim Limit", + "type": "integer" + }, + "claim_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim Limit Reached" + }, + "claims_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claims Selected" + }, + "input_truncated": { + "default": false, + "title": "Input Truncated", + "type": "boolean" + }, + "issues": { + "default": 0, + "title": "Issues", + "type": "integer" + }, + "verifications": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerificationCounts" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewSummary", + "type": "object" + }, + "ReviewVerificationCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "planned": { + "default": 0, + "title": "Planned", + "type": "integer" + } + }, + "title": "ReviewVerificationCounts", + "type": "object" + }, + "SuggestedEdit": { + "additionalProperties": true, + "description": "One replacement in the draft: the span ``start``..``end`` of the\n``text`` you sent (Unicode code points, ``end`` exclusive, as in\n``Position``), ``text`` exactly that slice, and ``replacement`` what takes\nits place (``\"\"`` deletes it). ``position`` is the index of the claim\nrow's ``positions`` entry the edit sits in, for grouping by passage.\n\nCompare ``text`` with your draft before you apply an edit, so a draft that\nchanged since is never edited in the wrong place.", + "properties": { + "end": { + "default": 0, + "title": "End", + "type": "integer" + }, + "position": { + "default": 0, + "title": "Position", + "type": "integer" + }, + "replacement": { + "default": "", + "title": "Replacement", + "type": "string" + }, + "start": { + "default": 0, + "title": "Start", + "type": "integer" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "SuggestedEdit", + "type": "object" + }, + "SuggestedEdits": { + "additionalProperties": true, + "description": "The smallest edits to the draft that make it say what the claim's\n``suggested_rewrite`` says (the deep check's, or the quick check's on a\nclaim that stayed on the quick verdict), in the draft's own language\n(``review(..., suggest_edits=True)``).\n\n``status`` is ``\"pending\"`` while they are computed (``edits`` is\n``None``; keep polling) and ``\"completed\"`` once settled, which includes\nsettling on none (``edits == []``: no edit could be made safely, or it\ncould not be computed). They are not themselves verified:\nreview them before you publish.", + "properties": { + "edits": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/SuggestedEdit" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Edits" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "SuggestedEdits", + "type": "object" + } + }, + "additionalProperties": true, + "description": "``GET /reviews/{review_id}?view=issues``: the envelope, no ``claims``.", + "properties": { + "citation_failures": { + "items": { + "$ref": "#/$defs/ReviewCitationFailure" + }, + "title": "Citation Failures", + "type": "array" + }, + "citation_issues": { + "items": { + "$ref": "#/$defs/ReviewCitationIssue" + }, + "title": "Citation Issues", + "type": "array" + }, + "completed_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Completed At" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "credits": { + "$ref": "#/$defs/ReviewCredits" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "failures": { + "items": { + "$ref": "#/$defs/ReviewFailure" + }, + "title": "Failures", + "type": "array" + }, + "issues": { + "items": { + "$ref": "#/$defs/ReviewIssue" + }, + "title": "Issues", + "type": "array" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "more_citations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ReviewMoreCitation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Citations" + }, + "more_claim_locations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ClaimLocation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claim Locations" + }, + "more_claims": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claims" + }, + "outcome": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Outcome" + }, + "policy": { + "$ref": "#/$defs/EscalationPolicy" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "review_id": { + "default": "", + "title": "Review Id", + "type": "string" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "summary": { + "$ref": "#/$defs/ReviewSummary" + }, + "view": { + "default": "issues", + "title": "View", + "type": "string" + } + }, + "title": "ReviewIssues", + "type": "object" + }, + "ReviewIssues:validation": { + "$defs": { + "ClaimLocation": { + "additionalProperties": true, + "description": "Where the submitted text makes one claim.\n\n``claim`` is exactly as in the claim list it belongs to\n(``ExtractedClaims.claim`` / ``identified_claims``, or a review's\n``more_claims``). ``positions`` lists every place the text makes it, in\ntext order, at most 10. It is ``None`` only when that claim could not be\nplaced; on ``/extract`` every returned claim is placed.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "positions": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/Position" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Positions" + } + }, + "title": "ClaimLocation", + "type": "object" + }, + "Escalation": { + "additionalProperties": true, + "description": "Why a claim was, or was not, deep-checked.\n\n``matched_rules`` lists the rules the quick check matched (``verdict``,\n``confidence``, both, or neither). ``disposition`` says what happened:\n``planned`` (deep-checked), ``not_selected`` (no rule matched), ``cap``\n(matched, but ``max_verifications`` was reached), ``credits`` (matched,\nbut the balance ran out) or ``account_cap`` (matched, but the account's\nallowance of concurrent deep checks was reached). To deep-check the\n``cap`` rows yourself, send their claims to ``verify_batch_and_wait``.", + "properties": { + "disposition": { + "default": "", + "title": "Disposition", + "type": "string" + }, + "matched_rules": { + "items": { + "type": "string" + }, + "title": "Matched Rules", + "type": "array" + } + }, + "title": "Escalation", + "type": "object" + }, + "EscalationPolicy": { + "additionalProperties": true, + "description": "Which quick-checked claims get a deep check, as the review RESOLVED it.\n\nA claim is deep-checked when its quick verdict is in ``verdicts`` OR its\nconfidence band is in ``confidence``, up to ``max_verifications`` of them,\nat ``depth``. ``max_assessments`` is how many of the draft's claims, most\ncheck-worthy first, got a quick verdict.", + "properties": { + "confidence": { + "items": { + "type": "string" + }, + "title": "Confidence", + "type": "array" + }, + "depth": { + "default": "standard", + "title": "Depth", + "type": "string" + }, + "max_assessments": { + "default": 20, + "title": "Max Assessments", + "type": "integer" + }, + "max_citations": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Max Citations" + }, + "max_verifications": { + "default": 5, + "title": "Max Verifications", + "type": "integer" + }, + "suggest_edits": { + "default": false, + "title": "Suggest Edits", + "type": "boolean" + }, + "verdicts": { + "items": { + "type": "string" + }, + "title": "Verdicts", + "type": "array" + } + }, + "title": "EscalationPolicy", + "type": "object" + }, + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + }, + "ReviewAssessmentCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + } + }, + "title": "ReviewAssessmentCounts", + "type": "object" + }, + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewCitationDifference": { + "additionalProperties": true, + "description": "One way the reference differs from the registry's record. ``field``\nis ``title``, ``authors``, ``year`` or ``journal``.", + "properties": { + "cited": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited" + }, + "field": { + "default": "", + "title": "Field", + "type": "string" + }, + "registered": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Registered" + } + }, + "title": "ReviewCitationDifference", + "type": "object" + }, + "ReviewCitationFailure": { + "additionalProperties": true, + "description": "A citation whose check failed with nothing established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + } + }, + "title": "ReviewCitationFailure", + "type": "object" + }, + "ReviewCitationIssue": { + "additionalProperties": true, + "description": "A citation whose finding is an issue (see ``ReviewCitationResult``);\nmost serious first, then in the draft's order.\n\n``snippet`` and ``rationale`` are set only when ``source`` is\n``support``. On ``quote_not_in_source``, ``missing_quote`` is the quoted\nexcerpt that was not found. On ``metadata_mismatch``,\n``metadata_differences`` says what differs. ``failure`` is set when another part of the check failed after\nthe finding was established.", + "properties": { + "citation_index": { + "default": 0, + "title": "Citation Index", + "type": "integer" + }, + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "finding": { + "default": "", + "title": "Finding", + "type": "string" + }, + "metadata_differences": { + "items": { + "$ref": "#/$defs/ReviewCitationDifference" + }, + "title": "Metadata Differences", + "type": "array" + }, + "missing_quote": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Missing Quote" + }, + "page_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Page Title" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "quotes": { + "items": { + "type": "string" + }, + "title": "Quotes", + "type": "array" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "snippet": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Snippet" + }, + "source": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Source" + }, + "statement": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Statement" + } + }, + "title": "ReviewCitationIssue", + "type": "object" + }, + "ReviewCredits": { + "additionalProperties": true, + "description": "``charged`` is the net credits the review cost the account, its\ncitation checks included. It is final once no deep check or citation\ncheck is running: read it at ``completed``.", + "properties": { + "charged": { + "default": 0, + "title": "Charged", + "type": "integer" + } + }, + "title": "ReviewCredits", + "type": "object" + }, + "ReviewFailure": { + "additionalProperties": true, + "description": "A claim outside the issues whose work failed. ``stage`` is\n``assessment`` or ``verification``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "stage": { + "default": "", + "title": "Stage", + "type": "string" + } + }, + "title": "ReviewFailure", + "type": "object" + }, + "ReviewIssue": { + "additionalProperties": true, + "description": "A claim whose final verdict is ``False``, ``Mostly False`` or ``Mixed``.\n\n``source`` says which check the verdict comes from: ``verification`` (a\ndeep check, with ``verification_id``, ``url`` and ``key_finding``) or\n``assessment`` (the quick check only; ``escalation`` says why it was not\ndeep-checked, and ``rationale`` is the reviewers' note).\n``verified_claim`` is the deep check's wording of the claim when it\ndiffers from ``claim``. ``failure`` is set when the claim's deep check\nfailed.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "claim_index": { + "default": 0, + "title": "Claim Index", + "type": "integer" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "escalation": { + "anyOf": [ + { + "$ref": "#/$defs/Escalation" + }, + { + "type": "null" + } + ], + "default": null + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "rationale": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rationale" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "suggested_edits": { + "anyOf": [ + { + "$ref": "#/$defs/SuggestedEdits" + }, + { + "type": "null" + } + ], + "default": null + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_status": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Status" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "verified_claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verified Claim" + } + }, + "title": "ReviewIssue", + "type": "object" + }, + "ReviewMoreCitation": { + "additionalProperties": true, + "description": "A citation found in the draft past the ones this review checked:\nfound but not checked. Send it in a later request to check it.\n``sentence`` is the draft's sentence around it.", + "properties": { + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "sentence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Sentence" + } + }, + "title": "ReviewMoreCitation", + "type": "object" + }, + "ReviewSummary": { + "additionalProperties": true, + "description": "Counts over the review. A count is ``None`` until what it counts is\nknown (``claims_selected`` before the draft has been read).\n\nThe ``citation*`` counts are ``None`` (``citation_issues`` 0) on a review\nthat did not ask for the citation check.", + "properties": { + "assessments": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewAssessmentCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + }, + "citations_skipped": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Skipped" + }, + "claim_limit": { + "default": 20, + "title": "Claim Limit", + "type": "integer" + }, + "claim_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim Limit Reached" + }, + "claims_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claims Selected" + }, + "input_truncated": { + "default": false, + "title": "Input Truncated", + "type": "boolean" + }, + "issues": { + "default": 0, + "title": "Issues", + "type": "integer" + }, + "verifications": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerificationCounts" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewSummary", + "type": "object" + }, + "ReviewVerificationCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "planned": { + "default": 0, + "title": "Planned", + "type": "integer" + } + }, + "title": "ReviewVerificationCounts", + "type": "object" + }, + "SuggestedEdit": { + "additionalProperties": true, + "description": "One replacement in the draft: the span ``start``..``end`` of the\n``text`` you sent (Unicode code points, ``end`` exclusive, as in\n``Position``), ``text`` exactly that slice, and ``replacement`` what takes\nits place (``\"\"`` deletes it). ``position`` is the index of the claim\nrow's ``positions`` entry the edit sits in, for grouping by passage.\n\nCompare ``text`` with your draft before you apply an edit, so a draft that\nchanged since is never edited in the wrong place.", + "properties": { + "end": { + "default": 0, + "title": "End", + "type": "integer" + }, + "position": { + "default": 0, + "title": "Position", + "type": "integer" + }, + "replacement": { + "default": "", + "title": "Replacement", + "type": "string" + }, + "start": { + "default": 0, + "title": "Start", + "type": "integer" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "SuggestedEdit", + "type": "object" + }, + "SuggestedEdits": { + "additionalProperties": true, + "description": "The smallest edits to the draft that make it say what the claim's\n``suggested_rewrite`` says (the deep check's, or the quick check's on a\nclaim that stayed on the quick verdict), in the draft's own language\n(``review(..., suggest_edits=True)``).\n\n``status`` is ``\"pending\"`` while they are computed (``edits`` is\n``None``; keep polling) and ``\"completed\"`` once settled, which includes\nsettling on none (``edits == []``: no edit could be made safely, or it\ncould not be computed). They are not themselves verified:\nreview them before you publish.", + "properties": { + "edits": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/SuggestedEdit" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Edits" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + } + }, + "title": "SuggestedEdits", + "type": "object" + } + }, + "additionalProperties": true, + "description": "``GET /reviews/{review_id}?view=issues``: the envelope, no ``claims``.", + "properties": { + "citation_failures": { + "items": { + "$ref": "#/$defs/ReviewCitationFailure" + }, + "title": "Citation Failures", + "type": "array" + }, + "citation_issues": { + "items": { + "$ref": "#/$defs/ReviewCitationIssue" + }, + "title": "Citation Issues", + "type": "array" + }, + "completed_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Completed At" + }, + "created_at": { + "default": "", + "title": "Created At", + "type": "string" + }, + "credits": { + "$ref": "#/$defs/ReviewCredits" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "failures": { + "items": { + "$ref": "#/$defs/ReviewFailure" + }, + "title": "Failures", + "type": "array" + }, + "issues": { + "items": { + "$ref": "#/$defs/ReviewIssue" + }, + "title": "Issues", + "type": "array" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "more_citations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ReviewMoreCitation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Citations" + }, + "more_claim_locations": { + "anyOf": [ + { + "items": { + "$ref": "#/$defs/ClaimLocation" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claim Locations" + }, + "more_claims": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "More Claims" + }, + "outcome": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Outcome" + }, + "policy": { + "$ref": "#/$defs/EscalationPolicy" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "review_id": { + "default": "", + "title": "Review Id", + "type": "string" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "summary": { + "$ref": "#/$defs/ReviewSummary" + }, + "view": { + "default": "issues", + "title": "View", + "type": "string" + } + }, + "title": "ReviewIssues", + "type": "object" + }, + "ReviewMoreCitation:serialization": { + "$defs": { + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A citation found in the draft past the ones this review checked:\nfound but not checked. Send it in a later request to check it.\n``sentence`` is the draft's sentence around it.", + "properties": { + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "sentence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Sentence" + } + }, + "title": "ReviewMoreCitation", + "type": "object" + }, + "ReviewMoreCitation:validation": { + "$defs": { + "Position": { + "additionalProperties": true, + "description": "One place in the text you sent: a claim's passage, or a citation's\nstatement.\n\n``start`` and ``end`` index the ``text`` you sent, in Unicode code\npoints (not UTF-16 units or bytes), half-open: ``text[start:end]`` is\nthe passage in Python, ``end`` exclusive. Both are ``None`` when the\ninput was a URL: the page is not returned, so there is nothing to index,\nand ``text`` carries the passage instead.\n\n``text`` is the passage as it appears in the text. It is ``None`` on a\ncitation's ``position``, whose row already carries the ``statement``.", + "properties": { + "end": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "End" + }, + "start": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Start" + }, + "text": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Text" + } + }, + "title": "Position", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A citation found in the draft past the ones this review checked:\nfound but not checked. Send it in a later request to check it.\n``sentence`` is the draft's sentence around it.", + "properties": { + "cited_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cited Url" + }, + "doi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Doi" + }, + "index": { + "default": 0, + "title": "Index", + "type": "integer" + }, + "position": { + "anyOf": [ + { + "$ref": "#/$defs/Position" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Reference" + }, + "sentence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Sentence" + } + }, + "title": "ReviewMoreCitation", + "type": "object" + }, + "ReviewResult:serialization": { + "additionalProperties": true, + "description": "The one answer to read for a claim: the deep check's verdict when it\ncompleted, else the quick check's. ``source`` says which\n(``assessment`` or ``verification``).", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + } + }, + "title": "ReviewResult", + "type": "object" + }, + "ReviewResult:validation": { + "additionalProperties": true, + "description": "The one answer to read for a claim: the deep check's verdict when it\ncompleted, else the quick check's. ``source`` says which\n(``assessment`` or ``verification``).", + "properties": { + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "is_issue": { + "default": false, + "title": "Is Issue", + "type": "boolean" + }, + "source": { + "default": "", + "title": "Source", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + } + }, + "title": "ReviewResult", + "type": "object" + }, + "ReviewStarted:serialization": { + "additionalProperties": true, + "description": "Returned by ``POST /review`` (HTTP 202).\n\n``status`` is always ``\"queued\"``: the acceptance receipt, not the current\nstate. Read the review with ``client.get_review(review_id)``.", + "properties": { + "review_id": { + "default": "", + "title": "Review Id", + "type": "string" + }, + "status": { + "default": "queued", + "title": "Status", + "type": "string" + } + }, + "title": "ReviewStarted", + "type": "object" + }, + "ReviewStarted:validation": { + "additionalProperties": true, + "description": "Returned by ``POST /review`` (HTTP 202).\n\n``status`` is always ``\"queued\"``: the acceptance receipt, not the current\nstate. Read the review with ``client.get_review(review_id)``.", + "properties": { + "review_id": { + "default": "", + "title": "Review Id", + "type": "string" + }, + "status": { + "default": "queued", + "title": "Status", + "type": "string" + } + }, + "title": "ReviewStarted", + "type": "object" + }, + "ReviewSummary:serialization": { + "$defs": { + "ReviewAssessmentCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + } + }, + "title": "ReviewAssessmentCounts", + "type": "object" + }, + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewVerificationCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "planned": { + "default": 0, + "title": "Planned", + "type": "integer" + } + }, + "title": "ReviewVerificationCounts", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Counts over the review. A count is ``None`` until what it counts is\nknown (``claims_selected`` before the draft has been read).\n\nThe ``citation*`` counts are ``None`` (``citation_issues`` 0) on a review\nthat did not ask for the citation check.", + "properties": { + "assessments": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewAssessmentCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + }, + "citations_skipped": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Skipped" + }, + "claim_limit": { + "default": 20, + "title": "Claim Limit", + "type": "integer" + }, + "claim_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim Limit Reached" + }, + "claims_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claims Selected" + }, + "input_truncated": { + "default": false, + "title": "Input Truncated", + "type": "boolean" + }, + "issues": { + "default": 0, + "title": "Issues", + "type": "integer" + }, + "verifications": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerificationCounts" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewSummary", + "type": "object" + }, + "ReviewSummary:validation": { + "$defs": { + "ReviewAssessmentCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + } + }, + "title": "ReviewAssessmentCounts", + "type": "object" + }, + "ReviewCitationCheckCounts": { + "additionalProperties": true, + "description": "Three disjoint counts over the citation rows. ``checked``: a finding\nother than ``unchecked``. ``unchecked``: could not be checked, for a\nreason of the page or the draft. ``failed``: no finding, for a reason of\nours. A row still running is in none of the three.", + "properties": { + "checked": { + "default": 0, + "title": "Checked", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "unchecked": { + "default": 0, + "title": "Unchecked", + "type": "integer" + } + }, + "title": "ReviewCitationCheckCounts", + "type": "object" + }, + "ReviewVerificationCounts": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "planned": { + "default": 0, + "title": "Planned", + "type": "integer" + } + }, + "title": "ReviewVerificationCounts", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Counts over the review. A count is ``None`` until what it counts is\nknown (``claims_selected`` before the draft has been read).\n\nThe ``citation*`` counts are ``None`` (``citation_issues`` 0) on a review\nthat did not ask for the citation check.", + "properties": { + "assessments": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewAssessmentCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_checks": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewCitationCheckCounts" + }, + { + "type": "null" + } + ], + "default": null + }, + "citation_issues": { + "default": 0, + "title": "Citation Issues", + "type": "integer" + }, + "citation_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit" + }, + "citation_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citation Limit Reached" + }, + "citations_found": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Found" + }, + "citations_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Selected" + }, + "citations_skipped": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Citations Skipped" + }, + "claim_limit": { + "default": 20, + "title": "Claim Limit", + "type": "integer" + }, + "claim_limit_reached": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim Limit Reached" + }, + "claims_selected": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claims Selected" + }, + "input_truncated": { + "default": false, + "title": "Input Truncated", + "type": "boolean" + }, + "issues": { + "default": 0, + "title": "Issues", + "type": "integer" + }, + "verifications": { + "anyOf": [ + { + "$ref": "#/$defs/ReviewVerificationCounts" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "ReviewSummary", + "type": "object" + }, + "ReviewVerification:serialization": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "ReviewEntity": { + "additionalProperties": true, + "description": "An entity the deep check found in the claim. ``qid`` is its Wikidata\nid when resolved. Either may be ``None``.", + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "ReviewEntity", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A claim's deep check. ``status``: ``processing`` | ``completed`` |\n``failed``; while ``processing`` only ``status``, ``content_status`` and\nthe ids are set. ``content_status`` is ``purged`` once the verification\nwas deleted or removed by its account's retention period: the verdict and\nids stay, the text fields and links are ``None``.\n\n``visibility`` and ``depth`` are what the verification actually has: a\nverdict served from an earlier check keeps its own visibility and may be\n``standard`` for a ``low`` request. Sources are on the verification\nitself: ``client.verifications.get(verification_id)``, or ``url``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "content_status": { + "default": "available", + "title": "Content Status", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Depth" + }, + "domain": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Domain" + }, + "entities": { + "items": { + "$ref": "#/$defs/ReviewEntity" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Executive Summary" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Language" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "task_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Task Id" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "visibility": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Visibility" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "ReviewVerification", + "type": "object" + }, + "ReviewVerification:validation": { + "$defs": { + "FailureBlock": { + "additionalProperties": true, + "description": "Why a review, or one claim's work inside it, failed.\n\nThe same fields a failed ``GET /verify/status`` carries: ``failure_reason``\nis the specific cause (an open set, e.g. ``no_claim``,\n``insufficient_credits``, ``timeout``), ``failure_class`` the closed\n:data:`FailureClass`, ``retryable`` whether resending the same request can\nhelp, ``hint`` one sentence on what to do next and ``docs_url`` where the\nclass is explained.", + "properties": { + "docs_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Docs Url" + }, + "failure_class": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Class" + }, + "failure_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "", + "title": "Failure Reason" + }, + "hint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Hint" + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + } + }, + "title": "FailureBlock", + "type": "object" + }, + "ReviewEntity": { + "additionalProperties": true, + "description": "An entity the deep check found in the claim. ``qid`` is its Wikidata\nid when resolved. Either may be ``None``.", + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "ReviewEntity", + "type": "object" + } + }, + "additionalProperties": true, + "description": "A claim's deep check. ``status``: ``processing`` | ``completed`` |\n``failed``; while ``processing`` only ``status``, ``content_status`` and\nthe ids are set. ``content_status`` is ``purged`` once the verification\nwas deleted or removed by its account's retention period: the verdict and\nids stay, the text fields and links are ``None``.\n\n``visibility`` and ``depth`` are what the verification actually has: a\nverdict served from an earlier check keeps its own visibility and may be\n``standard`` for a ``low`` request. Sources are on the verification\nitself: ``client.verifications.get(verification_id)``, or ``url``.", + "properties": { + "claim": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Claim" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Confidence" + }, + "content_status": { + "default": "available", + "title": "Content Status", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Depth" + }, + "domain": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Domain" + }, + "entities": { + "items": { + "$ref": "#/$defs/ReviewEntity" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Executive Summary" + }, + "failure": { + "anyOf": [ + { + "$ref": "#/$defs/FailureBlock" + }, + { + "type": "null" + } + ], + "default": null + }, + "key_finding": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Key Finding" + }, + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Language" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "task_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Task Id" + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Url" + }, + "verdict": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verdict" + }, + "verification_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Id" + }, + "verification_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Verification Url" + }, + "visibility": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Visibility" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "ReviewVerification", + "type": "object" + }, + "ReviewVerificationCounts:serialization": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "planned": { + "default": 0, + "title": "Planned", + "type": "integer" + } + }, + "title": "ReviewVerificationCounts", + "type": "object" + }, + "ReviewVerificationCounts:validation": { + "additionalProperties": true, + "properties": { + "completed": { + "default": 0, + "title": "Completed", + "type": "integer" + }, + "failed": { + "default": 0, + "title": "Failed", + "type": "integer" + }, + "planned": { + "default": 0, + "title": "Planned", + "type": "integer" + } + }, + "title": "ReviewVerificationCounts", + "type": "object" + }, + "SimilarVerification:serialization": { + "additionalProperties": true, + "description": "An existing public verification that semantically resembles the submitted text.\n\nSame vocabulary as ``Verification`` \u2014 flat ``verdict`` / ``confidence`` /\n``lenz_score`` at top level, no nested ``Verdict`` object.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "distance": { + "default": 0.0, + "title": "Distance", + "type": "number" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "SimilarVerification", + "type": "object" + }, + "SimilarVerification:validation": { + "additionalProperties": true, + "description": "An existing public verification that semantically resembles the submitted text.\n\nSame vocabulary as ``Verification`` \u2014 flat ``verdict`` / ``confidence`` /\n``lenz_score`` at top level, no nested ``Verdict`` object.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "distance": { + "default": 0.0, + "title": "Distance", + "type": "number" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "SimilarVerification", + "type": "object" + }, + "Source:serialization": { + "additionalProperties": true, + "description": "A single citation backing a verification.", + "properties": { + "date": { + "default": "", + "title": "Date", + "type": "string" + }, + "snippet": { + "default": "", + "title": "Snippet", + "type": "string" + }, + "source_name": { + "default": "", + "title": "Source Name", + "type": "string" + }, + "title": { + "default": "", + "title": "Title", + "type": "string" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + } + }, + "title": "Source", + "type": "object" + }, + "Source:validation": { + "additionalProperties": true, + "description": "A single citation backing a verification.", + "properties": { + "date": { + "default": "", + "title": "Date", + "type": "string" + }, + "snippet": { + "default": "", + "title": "Snippet", + "type": "string" + }, + "source_name": { + "default": "", + "title": "Source Name", + "type": "string" + }, + "title": { + "default": "", + "title": "Title", + "type": "string" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + } + }, + "title": "Source", + "type": "object" + }, + "TaskAccepted:serialization": { + "additionalProperties": true, + "description": "Returned by ``POST /verify`` and per item of ``POST /verify/batch``.", + "properties": { + "claim_text": { + "default": "", + "title": "Claim Text", + "type": "string" + }, + "task_id": { + "default": "", + "title": "Task Id", + "type": "string" + } + }, + "title": "TaskAccepted", + "type": "object" + }, + "TaskAccepted:validation": { + "additionalProperties": true, + "description": "Returned by ``POST /verify`` and per item of ``POST /verify/batch``.", + "properties": { + "claim_text": { + "default": "", + "title": "Claim Text", + "type": "string" + }, + "task_id": { + "default": "", + "title": "Task Id", + "type": "string" + } + }, + "title": "TaskAccepted", + "type": "object" + }, + "TaskStatus:serialization": { + "$defs": { + "Assessment": { + "additionalProperties": true, + "description": "One reviewer's structured assessment.\n\nCurrent verifications carry three reviewers, ``Reviewer A`` to\n``Reviewer C``, all running the same checks over the evidence, plus\n``Reviewer D`` and ``Reviewer E`` when those three disagree. Their\n``focus_area`` reads ``\"Sources, evidence fit and wording\"``, and\n``warnings`` holds the source issues, evidence gaps and precision issues\nthat reviewer found, in one list.\n\nOlder verifications carry specialist panelists instead, one warning\ncategory each: logical fallacies (Logic Examiner), precision issues\n(Precision Analyst), weakest sources (Source Auditor) and, before\n2026-06, missing context (Context Analyst).\n\n``panelist_name`` is a display value, not a stable key \u2014 don't branch\non it. ``score`` is a reviewer-level 1-10 sub-score, distinct from the\ntop-level ``lenz_score`` on a ``Verification``.", + "properties": { + "focus_area": { + "default": "", + "title": "Focus Area", + "type": "string" + }, + "panelist_name": { + "default": "", + "title": "Panelist Name", + "type": "string" + }, + "reasoning": { + "default": "", + "title": "Reasoning", + "type": "string" + }, + "score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Score" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Assessment", + "type": "object" + }, + "Audit": { + "additionalProperties": true, + "description": "Nested explainability block \u2014 for callers who want the panel's work.", + "properties": { + "adjudication_summary": { + "default": "", + "title": "Adjudication Summary", + "type": "string" + }, + "assessments": { + "items": { + "$ref": "#/$defs/Assessment" + }, + "title": "Assessments", + "type": "array" + }, + "debate_con": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "debate_pro": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "panel_agreement": { + "default": "", + "title": "Panel Agreement", + "type": "string" + } + }, + "title": "Audit", + "type": "object" + }, + "CandidateClaim": { + "additionalProperties": true, + "description": "One of multiple distinct claims framing found in the submitted text.", + "properties": { + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "CandidateClaim", + "type": "object" + }, + "Coverage": { + "additionalProperties": true, + "description": "Whether this verdict carries Lenz's warranty, for YOUR account.\n\nPresent only when covered verification is enabled on the account's plan;\n``None`` otherwise. It describes the pair (your account, this analysis),\nnot the analysis alone \u2014 two accounts can hold two certificates over one\ncached verdict, so the block you see is never another customer's.\n\n``reasons`` is empty exactly when ``status`` is not ``\"uncovered\"``.\n\nThe money fields are three, not two: ``currency`` is ISO 4217 and the\namounts are integers in **major units** \u2014 ``cap=10000`` means ten\nthousand, not a hundred. They are contract figures, not amounts a payment\nprocessor charges. Read ``currency``; do not assume EUR.", + "properties": { + "aggregate": { + "default": 0, + "title": "Aggregate", + "type": "integer" + }, + "as_of": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "As Of" + }, + "cap": { + "default": 0, + "title": "Cap", + "type": "integer" + }, + "certificate_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Id" + }, + "certificate_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Url" + }, + "currency": { + "default": "", + "title": "Currency", + "type": "string" + }, + "reasons": { + "items": { + "type": "string" + }, + "title": "Reasons", + "type": "array" + }, + "status": { + "default": "uncovered", + "title": "Status", + "type": "string" + }, + "terms_version": { + "default": "", + "title": "Terms Version", + "type": "string" + } + }, + "title": "Coverage", + "type": "object" + }, + "DebateSide": { + "additionalProperties": true, + "description": "One side of the adversarial debate transcript.", + "properties": { + "argument": { + "default": "", + "title": "Argument", + "type": "string" + }, + "rebuttal": { + "default": "", + "title": "Rebuttal", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "DebateSide", + "type": "object" + }, + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "Progress": { + "additionalProperties": true, + "description": "Where a running verification has got to. Advisory \u2014 never results.\n\n``step`` is one of ``starting`` / ``framing`` / ``research`` / ``debate``\n/ ``adjudication`` / ``conclusion``. ``index`` is the 1-based stage\nposition (0 while ``starting``) out of ``total``; read ``total`` off the\nresponse rather than hard-coding it. ``poll_after_seconds`` is how long\nto wait before looking again \u2014 :meth:`Lenz.verify_and_wait` honours it\nfor you. ``elapsed_seconds`` is how long the run has been going, a\nmeasurement rather than an estimate of what is left.\n\n``index`` is stage POSITION, not elapsed work: the stages are uneven, so\na bar driven by it sits on ``research`` for roughly half the run.\n\n``step`` stays a plain ``str``, not a ``Literal`` \u2014 an SDK that\nhard-rejects a stage name the server adds later is worse than one that\npasses it through.\n\nThis was a plain ``dict`` up to 2.10.0. The mapping methods below keep\n``p[\"step\"]``, ``\"step\" in p``, ``p.keys()`` and ``dict(p)`` working on a\n2.x minor; they are deprecated and go in 3.0.0. Use attributes.", + "properties": { + "elapsed_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Elapsed Seconds" + }, + "index": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Index" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "step": { + "default": "", + "title": "Step", + "type": "string" + }, + "total": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Total" + } + }, + "title": "Progress", + "type": "object" + }, + "SimilarVerification": { + "additionalProperties": true, + "description": "An existing public verification that semantically resembles the submitted text.\n\nSame vocabulary as ``Verification`` \u2014 flat ``verdict`` / ``confidence`` /\n``lenz_score`` at top level, no nested ``Verdict`` object.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "distance": { + "default": 0.0, + "title": "Distance", + "type": "number" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "SimilarVerification", + "type": "object" + }, + "Source": { + "additionalProperties": true, + "description": "A single citation backing a verification.", + "properties": { + "date": { + "default": "", + "title": "Date", + "type": "string" + }, + "snippet": { + "default": "", + "title": "Snippet", + "type": "string" + }, + "source_name": { + "default": "", + "title": "Source Name", + "type": "string" + }, + "title": { + "default": "", + "title": "Title", + "type": "string" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + } + }, + "title": "Source", + "type": "object" + }, + "Verification": { + "additionalProperties": true, + "description": "Full verification report \u2014 returned by ``verify_and_wait``,\n``verifications.get``, the ``/verify/status/{task_id}`` polling\nendpoint, and the webhook payload.\n\nThe verdict block is FLAT at top level (was nested ``Verdict`` object\npre-unify). ``created_at`` + ``modified_at`` are the only timestamp\nfields on the API surface \u2014 editorial ``published_at`` is internal-only.\n\n1.1.0: dropped ``url`` and ``visibility``. API claims are private by\ndefault and referenced by ``verification_id`` only. Cache-hit on\nanother customer's claim is transparent \u2014 the customer always sees\ntheir own ``verification_id``, never another customer's.\n\nLater: ``visibility`` returns \u2014 'private' | 'unlisted' | 'public'. It\nechoes what you set on submit ('private'/'unlisted' are settable;\n'public' can only be read, for listed claims). ``url`` stays dropped.", + "properties": { + "audit": { + "$ref": "#/$defs/Audit" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "coverage": { + "anyOf": [ + { + "$ref": "#/$defs/Coverage" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "default": "", + "title": "Depth", + "type": "string" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "presumed_intent": { + "default": "", + "title": "Presumed Intent", + "type": "string" + }, + "sources": { + "items": { + "$ref": "#/$defs/Source" + }, + "title": "Sources", + "type": "array" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + }, + "visibility": { + "default": "", + "title": "Visibility", + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Verification", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Returned by ``GET /verify/status/{task_id}``.", + "properties": { + "candidates": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidates", + "type": "array" + }, + "claims": { + "items": { + "$ref": "#/$defs/CandidateClaim" + }, + "title": "Claims", + "type": "array" + }, + "docs_url": { + "default": "", + "title": "Docs Url", + "type": "string" + }, + "error": { + "default": "", + "title": "Error", + "type": "string" + }, + "failure_class": { + "default": "", + "title": "Failure Class", + "type": "string" + }, + "failure_detail": { + "default": "", + "title": "Failure Detail", + "type": "string" + }, + "failure_reason": { + "default": "", + "title": "Failure Reason", + "type": "string" + }, + "hint": { + "default": "", + "title": "Hint", + "type": "string" + }, + "progress": { + "$ref": "#/$defs/Progress" + }, + "reason": { + "default": "", + "title": "Reason", + "type": "string" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/Verification" + }, + { + "type": "null" + } + ], + "default": null + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + }, + "similar_claims": { + "deprecated": true, + "items": { + "$ref": "#/$defs/SimilarVerification" + }, + "title": "Similar Claims", + "type": "array" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "task_id": { + "default": "", + "title": "Task Id", + "type": "string" + } + }, + "title": "TaskStatus", + "type": "object" + }, + "TaskStatus:validation": { + "$defs": { + "Assessment": { + "additionalProperties": true, + "description": "One reviewer's structured assessment.\n\nCurrent verifications carry three reviewers, ``Reviewer A`` to\n``Reviewer C``, all running the same checks over the evidence, plus\n``Reviewer D`` and ``Reviewer E`` when those three disagree. Their\n``focus_area`` reads ``\"Sources, evidence fit and wording\"``, and\n``warnings`` holds the source issues, evidence gaps and precision issues\nthat reviewer found, in one list.\n\nOlder verifications carry specialist panelists instead, one warning\ncategory each: logical fallacies (Logic Examiner), precision issues\n(Precision Analyst), weakest sources (Source Auditor) and, before\n2026-06, missing context (Context Analyst).\n\n``panelist_name`` is a display value, not a stable key \u2014 don't branch\non it. ``score`` is a reviewer-level 1-10 sub-score, distinct from the\ntop-level ``lenz_score`` on a ``Verification``.", + "properties": { + "focus_area": { + "default": "", + "title": "Focus Area", + "type": "string" + }, + "panelist_name": { + "default": "", + "title": "Panelist Name", + "type": "string" + }, + "reasoning": { + "default": "", + "title": "Reasoning", + "type": "string" + }, + "score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Score" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Assessment", + "type": "object" + }, + "Audit": { + "additionalProperties": true, + "description": "Nested explainability block \u2014 for callers who want the panel's work.", + "properties": { + "adjudication_summary": { + "default": "", + "title": "Adjudication Summary", + "type": "string" + }, + "assessments": { + "items": { + "$ref": "#/$defs/Assessment" + }, + "title": "Assessments", + "type": "array" + }, + "debate_con": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "debate_pro": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "panel_agreement": { + "default": "", + "title": "Panel Agreement", + "type": "string" + } + }, + "title": "Audit", + "type": "object" + }, + "CandidateClaim": { + "additionalProperties": true, + "description": "One of multiple distinct claims framing found in the submitted text.", + "properties": { + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "text": { + "default": "", + "title": "Text", + "type": "string" + } + }, + "title": "CandidateClaim", + "type": "object" + }, + "Coverage": { + "additionalProperties": true, + "description": "Whether this verdict carries Lenz's warranty, for YOUR account.\n\nPresent only when covered verification is enabled on the account's plan;\n``None`` otherwise. It describes the pair (your account, this analysis),\nnot the analysis alone \u2014 two accounts can hold two certificates over one\ncached verdict, so the block you see is never another customer's.\n\n``reasons`` is empty exactly when ``status`` is not ``\"uncovered\"``.\n\nThe money fields are three, not two: ``currency`` is ISO 4217 and the\namounts are integers in **major units** \u2014 ``cap=10000`` means ten\nthousand, not a hundred. They are contract figures, not amounts a payment\nprocessor charges. Read ``currency``; do not assume EUR.", + "properties": { + "aggregate": { + "default": 0, + "title": "Aggregate", + "type": "integer" + }, + "as_of": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "As Of" + }, + "cap": { + "default": 0, + "title": "Cap", + "type": "integer" + }, + "certificate_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Id" + }, + "certificate_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Url" + }, + "currency": { + "default": "", + "title": "Currency", + "type": "string" + }, + "reasons": { + "items": { + "type": "string" + }, + "title": "Reasons", + "type": "array" + }, + "status": { + "default": "uncovered", + "title": "Status", + "type": "string" + }, + "terms_version": { + "default": "", + "title": "Terms Version", + "type": "string" + } + }, + "title": "Coverage", + "type": "object" + }, + "DebateSide": { + "additionalProperties": true, + "description": "One side of the adversarial debate transcript.", + "properties": { + "argument": { + "default": "", + "title": "Argument", + "type": "string" + }, + "rebuttal": { + "default": "", + "title": "Rebuttal", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "DebateSide", + "type": "object" + }, + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "Progress": { + "additionalProperties": true, + "description": "Where a running verification has got to. Advisory \u2014 never results.\n\n``step`` is one of ``starting`` / ``framing`` / ``research`` / ``debate``\n/ ``adjudication`` / ``conclusion``. ``index`` is the 1-based stage\nposition (0 while ``starting``) out of ``total``; read ``total`` off the\nresponse rather than hard-coding it. ``poll_after_seconds`` is how long\nto wait before looking again \u2014 :meth:`Lenz.verify_and_wait` honours it\nfor you. ``elapsed_seconds`` is how long the run has been going, a\nmeasurement rather than an estimate of what is left.\n\n``index`` is stage POSITION, not elapsed work: the stages are uneven, so\na bar driven by it sits on ``research`` for roughly half the run.\n\n``step`` stays a plain ``str``, not a ``Literal`` \u2014 an SDK that\nhard-rejects a stage name the server adds later is worse than one that\npasses it through.\n\nThis was a plain ``dict`` up to 2.10.0. The mapping methods below keep\n``p[\"step\"]``, ``\"step\" in p``, ``p.keys()`` and ``dict(p)`` working on a\n2.x minor; they are deprecated and go in 3.0.0. Use attributes.", + "properties": { + "elapsed_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Elapsed Seconds" + }, + "index": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Index" + }, + "poll_after_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Poll After Seconds" + }, + "step": { + "default": "", + "title": "Step", + "type": "string" + }, + "total": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Total" + } + }, + "title": "Progress", + "type": "object" + }, + "SimilarVerification": { + "additionalProperties": true, + "description": "An existing public verification that semantically resembles the submitted text.\n\nSame vocabulary as ``Verification`` \u2014 flat ``verdict`` / ``confidence`` /\n``lenz_score`` at top level, no nested ``Verdict`` object.", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "distance": { + "default": 0.0, + "title": "Distance", + "type": "number" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "SimilarVerification", + "type": "object" + }, + "Source": { + "additionalProperties": true, + "description": "A single citation backing a verification.", + "properties": { + "date": { + "default": "", + "title": "Date", + "type": "string" + }, + "snippet": { + "default": "", + "title": "Snippet", + "type": "string" + }, + "source_name": { + "default": "", + "title": "Source Name", + "type": "string" + }, + "title": { + "default": "", + "title": "Title", + "type": "string" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + } + }, + "title": "Source", + "type": "object" + }, + "Verification": { + "additionalProperties": true, + "description": "Full verification report \u2014 returned by ``verify_and_wait``,\n``verifications.get``, the ``/verify/status/{task_id}`` polling\nendpoint, and the webhook payload.\n\nThe verdict block is FLAT at top level (was nested ``Verdict`` object\npre-unify). ``created_at`` + ``modified_at`` are the only timestamp\nfields on the API surface \u2014 editorial ``published_at`` is internal-only.\n\n1.1.0: dropped ``url`` and ``visibility``. API claims are private by\ndefault and referenced by ``verification_id`` only. Cache-hit on\nanother customer's claim is transparent \u2014 the customer always sees\ntheir own ``verification_id``, never another customer's.\n\nLater: ``visibility`` returns \u2014 'private' | 'unlisted' | 'public'. It\nechoes what you set on submit ('private'/'unlisted' are settable;\n'public' can only be read, for listed claims). ``url`` stays dropped.", + "properties": { + "audit": { + "$ref": "#/$defs/Audit" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "coverage": { + "anyOf": [ + { + "$ref": "#/$defs/Coverage" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "default": "", + "title": "Depth", + "type": "string" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "presumed_intent": { + "default": "", + "title": "Presumed Intent", + "type": "string" + }, + "sources": { + "items": { + "$ref": "#/$defs/Source" + }, + "title": "Sources", + "type": "array" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + }, + "visibility": { + "default": "", + "title": "Visibility", + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Verification", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Returned by ``GET /verify/status/{task_id}``.", + "properties": { + "candidates": { + "deprecated": true, + "items": { + "type": "string" + }, + "title": "Candidates", + "type": "array" + }, + "claims": { + "items": { + "$ref": "#/$defs/CandidateClaim" + }, + "title": "Claims", + "type": "array" + }, + "docs_url": { + "default": "", + "title": "Docs Url", + "type": "string" + }, + "error": { + "default": "", + "title": "Error", + "type": "string" + }, + "failure_class": { + "default": "", + "title": "Failure Class", + "type": "string" + }, + "failure_detail": { + "default": "", + "title": "Failure Detail", + "type": "string" + }, + "failure_reason": { + "default": "", + "title": "Failure Reason", + "type": "string" + }, + "hint": { + "default": "", + "title": "Hint", + "type": "string" + }, + "progress": { + "$ref": "#/$defs/Progress" + }, + "reason": { + "default": "", + "title": "Reason", + "type": "string" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/Verification" + }, + { + "type": "null" + } + ], + "default": null + }, + "retryable": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Retryable" + }, + "similar_claims": { + "deprecated": true, + "items": { + "$ref": "#/$defs/SimilarVerification" + }, + "title": "Similar Claims", + "type": "array" + }, + "status": { + "default": "", + "title": "Status", + "type": "string" + }, + "task_id": { + "default": "", + "title": "Task Id", + "type": "string" + } + }, + "title": "TaskStatus", + "type": "object" + }, + "Usage:serialization": { + "$defs": { + "UsageCapacity": { + "additionalProperties": true, + "description": "DEPRECATED. One capability's share of the pool, in that capability's unit.\n\n**Removed 2026-11-29**, together with the per-block ``credits`` alias.\nRead :attr:`Usage.credits` and :attr:`Usage.costs` and do the division \u2014\nit is the same one this block does::\n\n remaining = u.credits.remaining // u.costs[capability]\n total = u.credits.total // u.costs[capability]\n used = total - remaining\n\nTwo capabilities at the same price emit identical objects \u2014 ``ask`` and\n``assess`` are both 1 credit \u2014 because there is one balance behind all of\nthem, not a per-capability allowance.\n\nThese are **projections, not allowances**. Every billable capability draws\non the single balance in :attr:`Usage.credits`, at the weight in\n:attr:`Usage.costs`; this block answers \"how many ``/verify`` calls could I\nstill make if I spent everything on them\". Spending on any capability moves\nevery block, and the division floors \u2014 a ``verify`` block (weight 10) ticks\nonce per 10 credits spent anywhere.\n\n- ``quota_*`` \u2014 the monthly allowance projected into this unit; resets\n every period (see :attr:`Usage.quota_resets_at`). ``quota_used`` is\n derived as ``quota_total - quota_remaining``, so ``quota_used +\n quota_remaining == quota_total`` always holds.\n- ``bonus`` \u2014 :attr:`UsageCredits.extra`, the non-expiring part of the\n balance, in this unit. A user holding 5 extra credits sees\n ``assess.bonus == 5`` and ``verify.bonus == 0``: 5 credits does not\n buy a verification.\n\n``remaining`` is the usable capacity across both buckets.", + "properties": { + "bonus": { + "default": 0, + "title": "Bonus", + "type": "integer" + }, + "credits": { + "default": 0, + "deprecated": true, + "title": "Credits", + "type": "integer" + }, + "quota_remaining": { + "default": 0, + "title": "Quota Remaining", + "type": "integer" + }, + "quota_total": { + "default": 0, + "title": "Quota Total", + "type": "integer" + }, + "quota_used": { + "default": 0, + "title": "Quota Used", + "type": "integer" + }, + "remaining": { + "default": 0, + "title": "Remaining", + "type": "integer" + } + }, + "title": "UsageCapacity", + "type": "object" + }, + "UsageCredits": { + "additionalProperties": true, + "description": "The account's credit balance \u2014 the one pool every capability spends.\n\nEvery billable call debits this pool at the weight in :attr:`Usage.costs`\n(``/verify`` is 10 credits \u2014 5 at ``depth=\"low\"``, published as\n``cost_options[\"verify\"][\"depth\"][\"low\"]`` \u2014 ``/assess`` and ``/ask`` are 1, ``/extract`` is\nfree). Two buckets: the monthly allowance for the current plan, which\nresets at ``resets_at``, and non-expiring ``extra`` credits from grants and\ntop-ups, spent only once the allowance is gone. ``remaining`` covers both\nand is what a call is checked against. ``bonus`` is the deprecated old\nname of ``extra``, the same number, removed on 2026-11-29.\n\nServers predating the credit pool (before 2026-08-29) don't send this block\nat all, and it then reads as all-zero \u2014 check ``usage.credits.total``\nbefore trusting the balance.", + "properties": { + "bonus": { + "default": 0, + "deprecated": true, + "title": "Bonus", + "type": "integer" + }, + "extra": { + "default": 0, + "title": "Extra", + "type": "integer" + }, + "remaining": { + "default": 0, + "title": "Remaining", + "type": "integer" + }, + "resets_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Resets At" + }, + "total": { + "default": 0, + "title": "Total", + "type": "integer" + }, + "used": { + "default": 0, + "title": "Used", + "type": "integer" + } + }, + "title": "UsageCredits", + "type": "object" + }, + "UsageExtract": { + "additionalProperties": true, + "description": "Daily ``/extract`` usage \u2014 a per-day rate limit, not credit-based.", + "properties": { + "calls_today": { + "default": 0, + "title": "Calls Today", + "type": "integer" + }, + "daily_limit": { + "default": 0, + "title": "Daily Limit", + "type": "integer" + }, + "unlimited": { + "default": false, + "title": "Unlimited", + "type": "boolean" + } + }, + "title": "UsageExtract", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Returned by ``GET /me/usage`` \u2014 the account's balance and what it buys.\n\n``credits`` is the balance and ``costs`` is the price list (credits per\ncall, keyed by capability). The ``verify`` / ``ask`` / ``assess`` blocks\nare **projections** of that one pool into each capability's unit \u2014 read\nwhichever is convenient, they all describe the same money, and spending on\none moves all of them.\n\n``extract`` is free at the pool (``costs[\"extract\"] == 0``) and is bounded\nby a per-account daily fair-use cap instead; it rejects with 429, never\n402.\n\n``costs`` names capabilities, one entry each, at the default price.\nPrices that depend on a request PARAMETER live in :attr:`cost_options`,\nnested capability \u2192 parameter \u2192 value. Divide ``credits.remaining`` by one\nof those yourself for the low-depth count \u2014 there is deliberately no\n``verify_low`` block beside ``verify``.", + "properties": { + "ask": { + "$ref": "#/$defs/UsageCapacity" + }, + "assess": { + "$ref": "#/$defs/UsageCapacity" + }, + "cost_options": { + "additionalProperties": { + "additionalProperties": { + "additionalProperties": { + "type": "integer" + }, + "type": "object" + }, + "type": "object" + }, + "title": "Cost Options", + "type": "object" + }, + "costs": { + "additionalProperties": { + "type": "integer" + }, + "title": "Costs", + "type": "object" + }, + "credits": { + "$ref": "#/$defs/UsageCredits" + }, + "extract": { + "$ref": "#/$defs/UsageExtract" + }, + "has_webhook_secret": { + "default": false, + "title": "Has Webhook Secret", + "type": "boolean" + }, + "plan": { + "default": "", + "title": "Plan", + "type": "string" + }, + "plan_label": { + "default": "", + "title": "Plan Label", + "type": "string" + }, + "quota_resets_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Quota Resets At" + }, + "verify": { + "$ref": "#/$defs/UsageCapacity" + } + }, + "title": "Usage", + "type": "object" + }, + "Usage:validation": { + "$defs": { + "UsageCapacity": { + "additionalProperties": true, + "description": "DEPRECATED. One capability's share of the pool, in that capability's unit.\n\n**Removed 2026-11-29**, together with the per-block ``credits`` alias.\nRead :attr:`Usage.credits` and :attr:`Usage.costs` and do the division \u2014\nit is the same one this block does::\n\n remaining = u.credits.remaining // u.costs[capability]\n total = u.credits.total // u.costs[capability]\n used = total - remaining\n\nTwo capabilities at the same price emit identical objects \u2014 ``ask`` and\n``assess`` are both 1 credit \u2014 because there is one balance behind all of\nthem, not a per-capability allowance.\n\nThese are **projections, not allowances**. Every billable capability draws\non the single balance in :attr:`Usage.credits`, at the weight in\n:attr:`Usage.costs`; this block answers \"how many ``/verify`` calls could I\nstill make if I spent everything on them\". Spending on any capability moves\nevery block, and the division floors \u2014 a ``verify`` block (weight 10) ticks\nonce per 10 credits spent anywhere.\n\n- ``quota_*`` \u2014 the monthly allowance projected into this unit; resets\n every period (see :attr:`Usage.quota_resets_at`). ``quota_used`` is\n derived as ``quota_total - quota_remaining``, so ``quota_used +\n quota_remaining == quota_total`` always holds.\n- ``bonus`` \u2014 :attr:`UsageCredits.extra`, the non-expiring part of the\n balance, in this unit. A user holding 5 extra credits sees\n ``assess.bonus == 5`` and ``verify.bonus == 0``: 5 credits does not\n buy a verification.\n\n``remaining`` is the usable capacity across both buckets.", + "properties": { + "bonus": { + "default": 0, + "title": "Bonus", + "type": "integer" + }, + "credits": { + "default": 0, + "deprecated": true, + "title": "Credits", + "type": "integer" + }, + "quota_remaining": { + "default": 0, + "title": "Quota Remaining", + "type": "integer" + }, + "quota_total": { + "default": 0, + "title": "Quota Total", + "type": "integer" + }, + "quota_used": { + "default": 0, + "title": "Quota Used", + "type": "integer" + }, + "remaining": { + "default": 0, + "title": "Remaining", + "type": "integer" + } + }, + "title": "UsageCapacity", + "type": "object" + }, + "UsageCredits": { + "additionalProperties": true, + "description": "The account's credit balance \u2014 the one pool every capability spends.\n\nEvery billable call debits this pool at the weight in :attr:`Usage.costs`\n(``/verify`` is 10 credits \u2014 5 at ``depth=\"low\"``, published as\n``cost_options[\"verify\"][\"depth\"][\"low\"]`` \u2014 ``/assess`` and ``/ask`` are 1, ``/extract`` is\nfree). Two buckets: the monthly allowance for the current plan, which\nresets at ``resets_at``, and non-expiring ``extra`` credits from grants and\ntop-ups, spent only once the allowance is gone. ``remaining`` covers both\nand is what a call is checked against. ``bonus`` is the deprecated old\nname of ``extra``, the same number, removed on 2026-11-29.\n\nServers predating the credit pool (before 2026-08-29) don't send this block\nat all, and it then reads as all-zero \u2014 check ``usage.credits.total``\nbefore trusting the balance.", + "properties": { + "bonus": { + "default": 0, + "deprecated": true, + "title": "Bonus", + "type": "integer" + }, + "extra": { + "default": 0, + "title": "Extra", + "type": "integer" + }, + "remaining": { + "default": 0, + "title": "Remaining", + "type": "integer" + }, + "resets_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Resets At" + }, + "total": { + "default": 0, + "title": "Total", + "type": "integer" + }, + "used": { + "default": 0, + "title": "Used", + "type": "integer" + } + }, + "title": "UsageCredits", + "type": "object" + }, + "UsageExtract": { + "additionalProperties": true, + "description": "Daily ``/extract`` usage \u2014 a per-day rate limit, not credit-based.", + "properties": { + "calls_today": { + "default": 0, + "title": "Calls Today", + "type": "integer" + }, + "daily_limit": { + "default": 0, + "title": "Daily Limit", + "type": "integer" + }, + "unlimited": { + "default": false, + "title": "Unlimited", + "type": "boolean" + } + }, + "title": "UsageExtract", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Returned by ``GET /me/usage`` \u2014 the account's balance and what it buys.\n\n``credits`` is the balance and ``costs`` is the price list (credits per\ncall, keyed by capability). The ``verify`` / ``ask`` / ``assess`` blocks\nare **projections** of that one pool into each capability's unit \u2014 read\nwhichever is convenient, they all describe the same money, and spending on\none moves all of them.\n\n``extract`` is free at the pool (``costs[\"extract\"] == 0``) and is bounded\nby a per-account daily fair-use cap instead; it rejects with 429, never\n402.\n\n``costs`` names capabilities, one entry each, at the default price.\nPrices that depend on a request PARAMETER live in :attr:`cost_options`,\nnested capability \u2192 parameter \u2192 value. Divide ``credits.remaining`` by one\nof those yourself for the low-depth count \u2014 there is deliberately no\n``verify_low`` block beside ``verify``.", + "properties": { + "ask": { + "$ref": "#/$defs/UsageCapacity" + }, + "assess": { + "$ref": "#/$defs/UsageCapacity" + }, + "cost_options": { + "additionalProperties": { + "additionalProperties": { + "additionalProperties": { + "type": "integer" + }, + "type": "object" + }, + "type": "object" + }, + "title": "Cost Options", + "type": "object" + }, + "costs": { + "additionalProperties": { + "type": "integer" + }, + "title": "Costs", + "type": "object" + }, + "credits": { + "$ref": "#/$defs/UsageCredits" + }, + "extract": { + "$ref": "#/$defs/UsageExtract" + }, + "has_webhook_secret": { + "default": false, + "title": "Has Webhook Secret", + "type": "boolean" + }, + "plan": { + "default": "", + "title": "Plan", + "type": "string" + }, + "plan_label": { + "default": "", + "title": "Plan Label", + "type": "string" + }, + "quota_resets_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Quota Resets At" + }, + "verify": { + "$ref": "#/$defs/UsageCapacity" + } + }, + "title": "Usage", + "type": "object" + }, + "UsageCapacity:serialization": { + "additionalProperties": true, + "description": "DEPRECATED. One capability's share of the pool, in that capability's unit.\n\n**Removed 2026-11-29**, together with the per-block ``credits`` alias.\nRead :attr:`Usage.credits` and :attr:`Usage.costs` and do the division \u2014\nit is the same one this block does::\n\n remaining = u.credits.remaining // u.costs[capability]\n total = u.credits.total // u.costs[capability]\n used = total - remaining\n\nTwo capabilities at the same price emit identical objects \u2014 ``ask`` and\n``assess`` are both 1 credit \u2014 because there is one balance behind all of\nthem, not a per-capability allowance.\n\nThese are **projections, not allowances**. Every billable capability draws\non the single balance in :attr:`Usage.credits`, at the weight in\n:attr:`Usage.costs`; this block answers \"how many ``/verify`` calls could I\nstill make if I spent everything on them\". Spending on any capability moves\nevery block, and the division floors \u2014 a ``verify`` block (weight 10) ticks\nonce per 10 credits spent anywhere.\n\n- ``quota_*`` \u2014 the monthly allowance projected into this unit; resets\n every period (see :attr:`Usage.quota_resets_at`). ``quota_used`` is\n derived as ``quota_total - quota_remaining``, so ``quota_used +\n quota_remaining == quota_total`` always holds.\n- ``bonus`` \u2014 :attr:`UsageCredits.extra`, the non-expiring part of the\n balance, in this unit. A user holding 5 extra credits sees\n ``assess.bonus == 5`` and ``verify.bonus == 0``: 5 credits does not\n buy a verification.\n\n``remaining`` is the usable capacity across both buckets.", + "properties": { + "bonus": { + "default": 0, + "title": "Bonus", + "type": "integer" + }, + "credits": { + "default": 0, + "deprecated": true, + "title": "Credits", + "type": "integer" + }, + "quota_remaining": { + "default": 0, + "title": "Quota Remaining", + "type": "integer" + }, + "quota_total": { + "default": 0, + "title": "Quota Total", + "type": "integer" + }, + "quota_used": { + "default": 0, + "title": "Quota Used", + "type": "integer" + }, + "remaining": { + "default": 0, + "title": "Remaining", + "type": "integer" + } + }, + "title": "UsageCapacity", + "type": "object" + }, + "UsageCapacity:validation": { + "additionalProperties": true, + "description": "DEPRECATED. One capability's share of the pool, in that capability's unit.\n\n**Removed 2026-11-29**, together with the per-block ``credits`` alias.\nRead :attr:`Usage.credits` and :attr:`Usage.costs` and do the division \u2014\nit is the same one this block does::\n\n remaining = u.credits.remaining // u.costs[capability]\n total = u.credits.total // u.costs[capability]\n used = total - remaining\n\nTwo capabilities at the same price emit identical objects \u2014 ``ask`` and\n``assess`` are both 1 credit \u2014 because there is one balance behind all of\nthem, not a per-capability allowance.\n\nThese are **projections, not allowances**. Every billable capability draws\non the single balance in :attr:`Usage.credits`, at the weight in\n:attr:`Usage.costs`; this block answers \"how many ``/verify`` calls could I\nstill make if I spent everything on them\". Spending on any capability moves\nevery block, and the division floors \u2014 a ``verify`` block (weight 10) ticks\nonce per 10 credits spent anywhere.\n\n- ``quota_*`` \u2014 the monthly allowance projected into this unit; resets\n every period (see :attr:`Usage.quota_resets_at`). ``quota_used`` is\n derived as ``quota_total - quota_remaining``, so ``quota_used +\n quota_remaining == quota_total`` always holds.\n- ``bonus`` \u2014 :attr:`UsageCredits.extra`, the non-expiring part of the\n balance, in this unit. A user holding 5 extra credits sees\n ``assess.bonus == 5`` and ``verify.bonus == 0``: 5 credits does not\n buy a verification.\n\n``remaining`` is the usable capacity across both buckets.", + "properties": { + "bonus": { + "default": 0, + "title": "Bonus", + "type": "integer" + }, + "credits": { + "default": 0, + "deprecated": true, + "title": "Credits", + "type": "integer" + }, + "quota_remaining": { + "default": 0, + "title": "Quota Remaining", + "type": "integer" + }, + "quota_total": { + "default": 0, + "title": "Quota Total", + "type": "integer" + }, + "quota_used": { + "default": 0, + "title": "Quota Used", + "type": "integer" + }, + "remaining": { + "default": 0, + "title": "Remaining", + "type": "integer" + } + }, + "title": "UsageCapacity", + "type": "object" + }, + "UsageCredits:serialization": { + "additionalProperties": true, + "description": "The account's credit balance \u2014 the one pool every capability spends.\n\nEvery billable call debits this pool at the weight in :attr:`Usage.costs`\n(``/verify`` is 10 credits \u2014 5 at ``depth=\"low\"``, published as\n``cost_options[\"verify\"][\"depth\"][\"low\"]`` \u2014 ``/assess`` and ``/ask`` are 1, ``/extract`` is\nfree). Two buckets: the monthly allowance for the current plan, which\nresets at ``resets_at``, and non-expiring ``extra`` credits from grants and\ntop-ups, spent only once the allowance is gone. ``remaining`` covers both\nand is what a call is checked against. ``bonus`` is the deprecated old\nname of ``extra``, the same number, removed on 2026-11-29.\n\nServers predating the credit pool (before 2026-08-29) don't send this block\nat all, and it then reads as all-zero \u2014 check ``usage.credits.total``\nbefore trusting the balance.", + "properties": { + "bonus": { + "default": 0, + "deprecated": true, + "title": "Bonus", + "type": "integer" + }, + "extra": { + "default": 0, + "title": "Extra", + "type": "integer" + }, + "remaining": { + "default": 0, + "title": "Remaining", + "type": "integer" + }, + "resets_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Resets At" + }, + "total": { + "default": 0, + "title": "Total", + "type": "integer" + }, + "used": { + "default": 0, + "title": "Used", + "type": "integer" + } + }, + "title": "UsageCredits", + "type": "object" + }, + "UsageCredits:validation": { + "additionalProperties": true, + "description": "The account's credit balance \u2014 the one pool every capability spends.\n\nEvery billable call debits this pool at the weight in :attr:`Usage.costs`\n(``/verify`` is 10 credits \u2014 5 at ``depth=\"low\"``, published as\n``cost_options[\"verify\"][\"depth\"][\"low\"]`` \u2014 ``/assess`` and ``/ask`` are 1, ``/extract`` is\nfree). Two buckets: the monthly allowance for the current plan, which\nresets at ``resets_at``, and non-expiring ``extra`` credits from grants and\ntop-ups, spent only once the allowance is gone. ``remaining`` covers both\nand is what a call is checked against. ``bonus`` is the deprecated old\nname of ``extra``, the same number, removed on 2026-11-29.\n\nServers predating the credit pool (before 2026-08-29) don't send this block\nat all, and it then reads as all-zero \u2014 check ``usage.credits.total``\nbefore trusting the balance.", + "properties": { + "bonus": { + "default": 0, + "deprecated": true, + "title": "Bonus", + "type": "integer" + }, + "extra": { + "default": 0, + "title": "Extra", + "type": "integer" + }, + "remaining": { + "default": 0, + "title": "Remaining", + "type": "integer" + }, + "resets_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Resets At" + }, + "total": { + "default": 0, + "title": "Total", + "type": "integer" + }, + "used": { + "default": 0, + "title": "Used", + "type": "integer" + } + }, + "title": "UsageCredits", + "type": "object" + }, + "UsageExtract:serialization": { + "additionalProperties": true, + "description": "Daily ``/extract`` usage \u2014 a per-day rate limit, not credit-based.", + "properties": { + "calls_today": { + "default": 0, + "title": "Calls Today", + "type": "integer" + }, + "daily_limit": { + "default": 0, + "title": "Daily Limit", + "type": "integer" + }, + "unlimited": { + "default": false, + "title": "Unlimited", + "type": "boolean" + } + }, + "title": "UsageExtract", + "type": "object" + }, + "UsageExtract:validation": { + "additionalProperties": true, + "description": "Daily ``/extract`` usage \u2014 a per-day rate limit, not credit-based.", + "properties": { + "calls_today": { + "default": 0, + "title": "Calls Today", + "type": "integer" + }, + "daily_limit": { + "default": 0, + "title": "Daily Limit", + "type": "integer" + }, + "unlimited": { + "default": false, + "title": "Unlimited", + "type": "boolean" + } + }, + "title": "UsageExtract", + "type": "object" + }, + "Verification:serialization": { + "$defs": { + "Assessment": { + "additionalProperties": true, + "description": "One reviewer's structured assessment.\n\nCurrent verifications carry three reviewers, ``Reviewer A`` to\n``Reviewer C``, all running the same checks over the evidence, plus\n``Reviewer D`` and ``Reviewer E`` when those three disagree. Their\n``focus_area`` reads ``\"Sources, evidence fit and wording\"``, and\n``warnings`` holds the source issues, evidence gaps and precision issues\nthat reviewer found, in one list.\n\nOlder verifications carry specialist panelists instead, one warning\ncategory each: logical fallacies (Logic Examiner), precision issues\n(Precision Analyst), weakest sources (Source Auditor) and, before\n2026-06, missing context (Context Analyst).\n\n``panelist_name`` is a display value, not a stable key \u2014 don't branch\non it. ``score`` is a reviewer-level 1-10 sub-score, distinct from the\ntop-level ``lenz_score`` on a ``Verification``.", + "properties": { + "focus_area": { + "default": "", + "title": "Focus Area", + "type": "string" + }, + "panelist_name": { + "default": "", + "title": "Panelist Name", + "type": "string" + }, + "reasoning": { + "default": "", + "title": "Reasoning", + "type": "string" + }, + "score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Score" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Assessment", + "type": "object" + }, + "Audit": { + "additionalProperties": true, + "description": "Nested explainability block \u2014 for callers who want the panel's work.", + "properties": { + "adjudication_summary": { + "default": "", + "title": "Adjudication Summary", + "type": "string" + }, + "assessments": { + "items": { + "$ref": "#/$defs/Assessment" + }, + "title": "Assessments", + "type": "array" + }, + "debate_con": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "debate_pro": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "panel_agreement": { + "default": "", + "title": "Panel Agreement", + "type": "string" + } + }, + "title": "Audit", + "type": "object" + }, + "Coverage": { + "additionalProperties": true, + "description": "Whether this verdict carries Lenz's warranty, for YOUR account.\n\nPresent only when covered verification is enabled on the account's plan;\n``None`` otherwise. It describes the pair (your account, this analysis),\nnot the analysis alone \u2014 two accounts can hold two certificates over one\ncached verdict, so the block you see is never another customer's.\n\n``reasons`` is empty exactly when ``status`` is not ``\"uncovered\"``.\n\nThe money fields are three, not two: ``currency`` is ISO 4217 and the\namounts are integers in **major units** \u2014 ``cap=10000`` means ten\nthousand, not a hundred. They are contract figures, not amounts a payment\nprocessor charges. Read ``currency``; do not assume EUR.", + "properties": { + "aggregate": { + "default": 0, + "title": "Aggregate", + "type": "integer" + }, + "as_of": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "As Of" + }, + "cap": { + "default": 0, + "title": "Cap", + "type": "integer" + }, + "certificate_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Id" + }, + "certificate_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Url" + }, + "currency": { + "default": "", + "title": "Currency", + "type": "string" + }, + "reasons": { + "items": { + "type": "string" + }, + "title": "Reasons", + "type": "array" + }, + "status": { + "default": "uncovered", + "title": "Status", + "type": "string" + }, + "terms_version": { + "default": "", + "title": "Terms Version", + "type": "string" + } + }, + "title": "Coverage", + "type": "object" + }, + "DebateSide": { + "additionalProperties": true, + "description": "One side of the adversarial debate transcript.", + "properties": { + "argument": { + "default": "", + "title": "Argument", + "type": "string" + }, + "rebuttal": { + "default": "", + "title": "Rebuttal", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "DebateSide", + "type": "object" + }, + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "Source": { + "additionalProperties": true, + "description": "A single citation backing a verification.", + "properties": { + "date": { + "default": "", + "title": "Date", + "type": "string" + }, + "snippet": { + "default": "", + "title": "Snippet", + "type": "string" + }, + "source_name": { + "default": "", + "title": "Source Name", + "type": "string" + }, + "title": { + "default": "", + "title": "Title", + "type": "string" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + } + }, + "title": "Source", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Full verification report \u2014 returned by ``verify_and_wait``,\n``verifications.get``, the ``/verify/status/{task_id}`` polling\nendpoint, and the webhook payload.\n\nThe verdict block is FLAT at top level (was nested ``Verdict`` object\npre-unify). ``created_at`` + ``modified_at`` are the only timestamp\nfields on the API surface \u2014 editorial ``published_at`` is internal-only.\n\n1.1.0: dropped ``url`` and ``visibility``. API claims are private by\ndefault and referenced by ``verification_id`` only. Cache-hit on\nanother customer's claim is transparent \u2014 the customer always sees\ntheir own ``verification_id``, never another customer's.\n\nLater: ``visibility`` returns \u2014 'private' | 'unlisted' | 'public'. It\nechoes what you set on submit ('private'/'unlisted' are settable;\n'public' can only be read, for listed claims). ``url`` stays dropped.", + "properties": { + "audit": { + "$ref": "#/$defs/Audit" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "coverage": { + "anyOf": [ + { + "$ref": "#/$defs/Coverage" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "default": "", + "title": "Depth", + "type": "string" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "presumed_intent": { + "default": "", + "title": "Presumed Intent", + "type": "string" + }, + "sources": { + "items": { + "$ref": "#/$defs/Source" + }, + "title": "Sources", + "type": "array" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + }, + "visibility": { + "default": "", + "title": "Visibility", + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Verification", + "type": "object" + }, + "Verification:validation": { + "$defs": { + "Assessment": { + "additionalProperties": true, + "description": "One reviewer's structured assessment.\n\nCurrent verifications carry three reviewers, ``Reviewer A`` to\n``Reviewer C``, all running the same checks over the evidence, plus\n``Reviewer D`` and ``Reviewer E`` when those three disagree. Their\n``focus_area`` reads ``\"Sources, evidence fit and wording\"``, and\n``warnings`` holds the source issues, evidence gaps and precision issues\nthat reviewer found, in one list.\n\nOlder verifications carry specialist panelists instead, one warning\ncategory each: logical fallacies (Logic Examiner), precision issues\n(Precision Analyst), weakest sources (Source Auditor) and, before\n2026-06, missing context (Context Analyst).\n\n``panelist_name`` is a display value, not a stable key \u2014 don't branch\non it. ``score`` is a reviewer-level 1-10 sub-score, distinct from the\ntop-level ``lenz_score`` on a ``Verification``.", + "properties": { + "focus_area": { + "default": "", + "title": "Focus Area", + "type": "string" + }, + "panelist_name": { + "default": "", + "title": "Panelist Name", + "type": "string" + }, + "reasoning": { + "default": "", + "title": "Reasoning", + "type": "string" + }, + "score": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Score" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Assessment", + "type": "object" + }, + "Audit": { + "additionalProperties": true, + "description": "Nested explainability block \u2014 for callers who want the panel's work.", + "properties": { + "adjudication_summary": { + "default": "", + "title": "Adjudication Summary", + "type": "string" + }, + "assessments": { + "items": { + "$ref": "#/$defs/Assessment" + }, + "title": "Assessments", + "type": "array" + }, + "debate_con": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "debate_pro": { + "anyOf": [ + { + "$ref": "#/$defs/DebateSide" + }, + { + "type": "null" + } + ], + "default": null + }, + "panel_agreement": { + "default": "", + "title": "Panel Agreement", + "type": "string" + } + }, + "title": "Audit", + "type": "object" + }, + "Coverage": { + "additionalProperties": true, + "description": "Whether this verdict carries Lenz's warranty, for YOUR account.\n\nPresent only when covered verification is enabled on the account's plan;\n``None`` otherwise. It describes the pair (your account, this analysis),\nnot the analysis alone \u2014 two accounts can hold two certificates over one\ncached verdict, so the block you see is never another customer's.\n\n``reasons`` is empty exactly when ``status`` is not ``\"uncovered\"``.\n\nThe money fields are three, not two: ``currency`` is ISO 4217 and the\namounts are integers in **major units** \u2014 ``cap=10000`` means ten\nthousand, not a hundred. They are contract figures, not amounts a payment\nprocessor charges. Read ``currency``; do not assume EUR.", + "properties": { + "aggregate": { + "default": 0, + "title": "Aggregate", + "type": "integer" + }, + "as_of": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "As Of" + }, + "cap": { + "default": 0, + "title": "Cap", + "type": "integer" + }, + "certificate_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Id" + }, + "certificate_url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Certificate Url" + }, + "currency": { + "default": "", + "title": "Currency", + "type": "string" + }, + "reasons": { + "items": { + "type": "string" + }, + "title": "Reasons", + "type": "array" + }, + "status": { + "default": "uncovered", + "title": "Status", + "type": "string" + }, + "terms_version": { + "default": "", + "title": "Terms Version", + "type": "string" + } + }, + "title": "Coverage", + "type": "object" + }, + "DebateSide": { + "additionalProperties": true, + "description": "One side of the adversarial debate transcript.", + "properties": { + "argument": { + "default": "", + "title": "Argument", + "type": "string" + }, + "rebuttal": { + "default": "", + "title": "Rebuttal", + "type": "string" + }, + "role": { + "default": "", + "title": "Role", + "type": "string" + } + }, + "title": "DebateSide", + "type": "object" + }, + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "Source": { + "additionalProperties": true, + "description": "A single citation backing a verification.", + "properties": { + "date": { + "default": "", + "title": "Date", + "type": "string" + }, + "snippet": { + "default": "", + "title": "Snippet", + "type": "string" + }, + "source_name": { + "default": "", + "title": "Source Name", + "type": "string" + }, + "title": { + "default": "", + "title": "Title", + "type": "string" + }, + "url": { + "default": "", + "title": "Url", + "type": "string" + } + }, + "title": "Source", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Full verification report \u2014 returned by ``verify_and_wait``,\n``verifications.get``, the ``/verify/status/{task_id}`` polling\nendpoint, and the webhook payload.\n\nThe verdict block is FLAT at top level (was nested ``Verdict`` object\npre-unify). ``created_at`` + ``modified_at`` are the only timestamp\nfields on the API surface \u2014 editorial ``published_at`` is internal-only.\n\n1.1.0: dropped ``url`` and ``visibility``. API claims are private by\ndefault and referenced by ``verification_id`` only. Cache-hit on\nanother customer's claim is transparent \u2014 the customer always sees\ntheir own ``verification_id``, never another customer's.\n\nLater: ``visibility`` returns \u2014 'private' | 'unlisted' | 'public'. It\nechoes what you set on submit ('private'/'unlisted' are settable;\n'public' can only be read, for listed claims). ``url`` stays dropped.", + "properties": { + "audit": { + "$ref": "#/$defs/Audit" + }, + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "coverage": { + "anyOf": [ + { + "$ref": "#/$defs/Coverage" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "depth": { + "default": "", + "title": "Depth", + "type": "string" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "presumed_intent": { + "default": "", + "title": "Presumed Intent", + "type": "string" + }, + "sources": { + "items": { + "$ref": "#/$defs/Source" + }, + "title": "Sources", + "type": "array" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + }, + "visibility": { + "default": "", + "title": "Visibility", + "type": "string" + }, + "warnings": { + "items": { + "type": "string" + }, + "title": "Warnings", + "type": "array" + } + }, + "title": "Verification", + "type": "object" + }, + "VerificationList:serialization": { + "$defs": { + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "VerificationListItem": { + "additionalProperties": true, + "description": "Compact item for the verifications list endpoint and the public\nlibrary list. Slim shape \u2014 no ``url`` (reference by\n``verification_id``), no ``visibility`` (1.1.0).", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "VerificationListItem", + "type": "object" + } + }, + "additionalProperties": true, + "properties": { + "items": { + "items": { + "$ref": "#/$defs/VerificationListItem" + }, + "title": "Items", + "type": "array" + }, + "page": { + "default": 1, + "title": "Page", + "type": "integer" + }, + "page_size": { + "default": 20, + "title": "Page Size", + "type": "integer" + }, + "total": { + "default": 0, + "title": "Total", + "type": "integer" + } + }, + "title": "VerificationList", + "type": "object" + }, + "VerificationList:validation": { + "$defs": { + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + }, + "VerificationListItem": { + "additionalProperties": true, + "description": "Compact item for the verifications list endpoint and the public\nlibrary list. Slim shape \u2014 no ``url`` (reference by\n``verification_id``), no ``visibility`` (1.1.0).", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "VerificationListItem", + "type": "object" + } + }, + "additionalProperties": true, + "properties": { + "items": { + "items": { + "$ref": "#/$defs/VerificationListItem" + }, + "title": "Items", + "type": "array" + }, + "page": { + "default": 1, + "title": "Page", + "type": "integer" + }, + "page_size": { + "default": 20, + "title": "Page Size", + "type": "integer" + }, + "total": { + "default": 0, + "title": "Total", + "type": "integer" + } + }, + "title": "VerificationList", + "type": "object" + }, + "VerificationListItem:serialization": { + "$defs": { + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Compact item for the verifications list endpoint and the public\nlibrary list. Slim shape \u2014 no ``url`` (reference by\n``verification_id``), no ``visibility`` (1.1.0).", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "VerificationListItem", + "type": "object" + }, + "VerificationListItem:validation": { + "$defs": { + "EntityRef": { + "additionalProperties": true, + "description": "An entity referenced in the claim.\n\n``qid`` is the Wikidata Q identifier (e.g. ``Q42``) when the entity\nwas resolved against Lenz's internal catalog; ``None`` otherwise.", + "properties": { + "name": { + "default": "", + "title": "Name", + "type": "string" + }, + "qid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Qid" + } + }, + "title": "EntityRef", + "type": "object" + } + }, + "additionalProperties": true, + "description": "Compact item for the verifications list endpoint and the public\nlibrary list. Slim shape \u2014 no ``url`` (reference by\n``verification_id``), no ``visibility`` (1.1.0).", + "properties": { + "claim": { + "default": "", + "title": "Claim", + "type": "string" + }, + "confidence": { + "default": "low", + "title": "Confidence", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Created At" + }, + "domain": { + "default": "", + "title": "Domain", + "type": "string" + }, + "entities": { + "items": { + "$ref": "#/$defs/EntityRef" + }, + "title": "Entities", + "type": "array" + }, + "executive_summary": { + "default": "", + "title": "Executive Summary", + "type": "string" + }, + "key_finding": { + "default": "", + "title": "Key Finding", + "type": "string" + }, + "language": { + "default": "en", + "title": "Language", + "type": "string" + }, + "lenz_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Lenz Score" + }, + "modified_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Modified At" + }, + "suggested_rewrite": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Suggested Rewrite" + }, + "verdict": { + "default": "", + "title": "Verdict", + "type": "string" + }, + "verification_id": { + "default": "", + "title": "Verification Id", + "type": "string" + } + }, + "title": "VerificationListItem", + "type": "object" + } +} diff --git a/tests/parity_generate.py b/tests/parity_generate.py index e104cb9..cf386f2 100644 --- a/tests/parity_generate.py +++ b/tests/parity_generate.py @@ -15,21 +15,29 @@ import json import sys +from pathlib import Path from parity_observe import FIXTURES, load, names, observe from parity_requests import bodies +from parity_static import pickles, schemas import lenz_io def main() -> None: print(f"observing with lenz_io from {lenz_io.__file__}", file=sys.stderr) + if "--allow-current" not in sys.argv and Path(lenz_io.__file__).resolve().is_relative_to( + Path(__file__).resolve().parents[1] + ): + raise SystemExit("refusing: this is the current code; put the previous release first on PYTHONPATH") out = FIXTURES / "expected" out.mkdir(exist_ok=True) for name in names(): result = observe(name, load("legacy", name)) (out / name).write_text(json.dumps(result, indent=2, ensure_ascii=False, sort_keys=True) + "\n") (FIXTURES / "requests.json").write_text(json.dumps(bodies(), indent=2, sort_keys=True) + "\n") + (FIXTURES / "schemas.json").write_text(json.dumps(schemas(), indent=2, sort_keys=True) + "\n") + (FIXTURES / "pickles.json").write_text(json.dumps(pickles(), indent=2, sort_keys=True) + "\n") print(f"wrote {len(names())} files and requests.json", file=sys.stderr) diff --git a/tests/parity_observe.py b/tests/parity_observe.py index 242d5e0..0ed28d7 100644 --- a/tests/parity_observe.py +++ b/tests/parity_observe.py @@ -96,9 +96,9 @@ def attr_view(obj: Any, template: Any) -> Any: out[key] = MISSING if value is MISSING else attr_view(value, sub) return out if isinstance(template, list): - items = list(obj) if isinstance(obj, (list, tuple)) else [] - if len(items) != len(template): + if not isinstance(obj, (list, tuple)) or len(obj) != len(template): return _jsonable(obj) + items = list(obj) return [attr_view(o, t) for o, t in zip(items, template, strict=True)] return _jsonable(obj) @@ -186,8 +186,10 @@ def observe(name: str, fixture: dict[str, Any]) -> dict[str, Any]: cls = _model_for(name) if cls is None: return result - model = cls.model_validate(body) + model = _extract_via_client(name, body) if cls is models.ExtractedClaims else cls.model_validate(body) result["dump"] = model.model_dump(mode="json") + result["dump_unset"] = model.model_dump(mode="json", exclude_unset=True) + result["repr"] = repr(model) result["render_json"] = None if cls is models.ExtractedClaims: result["render"] = _render(render_mod.render_extract, model) @@ -225,6 +227,26 @@ def observe(name: str, fixture: dict[str, Any]) -> dict[str, Any]: return result +def located(name: str) -> bool: + """Whether the recorded /extract call asked to locate its claims.""" + return "locate" in name + + +def _extract_via_client(name: str, body: dict[str, Any]) -> Any: + """``client.extract`` on the recorded body, with the recorded ``locate``.""" + import respx + + from lenz_io.client import DEFAULT_BASE_URL + + client = Lenz(api_key="lenz_" + "0" * 32) + try: + with respx.mock(base_url=DEFAULT_BASE_URL) as mock: + mock.post("/extract").respond(200, json=body) + return client.extract(text="text", locate=True if located(name) else None) + finally: + client.close() + + def load(shape: str, name: str) -> dict[str, Any]: return json.loads((FIXTURES / shape / name).read_text()) diff --git a/tests/parity_static.py b/tests/parity_static.py new file mode 100644 index 0000000..8883f0d --- /dev/null +++ b/tests/parity_static.py @@ -0,0 +1,46 @@ +"""Model schemas and pickles, frozen by ``parity_generate.py`` from the +previous release (``schemas.json``, ``pickles.json``) and checked by +``test_parity.py``: this release must publish the same JSON schemas for every +model, and unpickle and dump what the previous release pickled.""" + +from __future__ import annotations + +import base64 +import pickle +import warnings +from typing import Any + +from parity_observe import _model_for, load, names +from pydantic import BaseModel + +from lenz_io import models + + +def model_classes() -> dict[str, type[BaseModel]]: + return { + name: obj + for name in models.__all__ + if isinstance(obj := getattr(models, name), type) and issubclass(obj, BaseModel) + } + + +def schemas() -> dict[str, Any]: + out = {} + for name, cls in model_classes().items(): + for mode in ("validation", "serialization"): + out[f"{name}:{mode}"] = cls.model_json_schema(mode=mode) + return out + + +def _pickle_names() -> list[str]: + return [n for n in names() if _model_for(n) is not None and load("legacy", n)["status"] < 400] + + +def pickles() -> dict[str, str]: + out = {} + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + for name in _pickle_names(): + model = _model_for(name).model_validate(load("legacy", name)["body"]) + out[name] = base64.b64encode(pickle.dumps(model, protocol=4)).decode() + return out diff --git a/tests/test_parity.py b/tests/test_parity.py index 90a942e..ee0b578 100644 --- a/tests/test_parity.py +++ b/tests/test_parity.py @@ -26,7 +26,10 @@ from typing import Any import pytest -from parity_observe import FIXTURES, MISSING, _model_for, attr_view, load, names, observe +from parity_observe import FIXTURES, MISSING, _extract_via_client, _model_for, attr_view, load, names, observe + +from lenz_io import models +from lenz_io.webhooks import parse_webhook EXPECTED = FIXTURES / "expected" @@ -38,8 +41,8 @@ # the server's sentences (error / failure text), the codes and field errors it # sends on a 422, `chain_id`, the review / citation-check webhook `task_id`, # and a row hint the newer shape does not carry. The single entries in -# ``KNOWN_GAPS`` below fall in those categories too, plus two where the two -# recordings simply hold different ids. +# ``KNOWN_GAPS`` below fall in those categories too, plus one where the two +# recordings number an id differently. #: An exception's text fields: built from the body's ``detail``. _MESSAGE_PATHS = ("message", "cause", "friendly_text", "payload_json.error.message") @@ -101,23 +104,9 @@ def _allowed(name: str, path: str, legacy: dict[str, Any], canonical: dict[str, ("extract__not_a_claim_beside_claims.json", "dump.status"): ( "the newer shape answers `ready` when claims came back beside a non-claim" ), - ("verify__list_200.json", "dump.items[1].verification_id"): "the two recordings list different verifications", - ("verify__list_200.json", "dump.items[1].created_at"): "the two recordings list different verifications", - ( - "verify__verification_200_covered.json", - "dump.coverage.certificate_id", - ): "the two recordings issued different certificates", - ( - "verify__verification_200_covered.json", - "dump.coverage.certificate_url", - ): "the two recordings issued different certificates", - ("review__get_completed_issues_all_verified.json", "dump.claims[1].verification.task_id"): ( - "the two recordings ran different tasks" + ("webhook__review_completed.json", "event.review.claims[0].verification.task_id"): ( + "the two recordings number their task ids differently (the newer payload has no delivery task_id)" ), - ( - "review__get_completed_issues_full.json", - "dump.claims[2].verification.task_id", - ): "the two recordings ran different tasks", } @@ -162,11 +151,23 @@ def test_original_shape_is_unchanged(name: str) -> None: def _canonical_view(name: str, expected: dict[str, Any]) -> dict[str, Any]: fixture = load("canonical", name) got = _old_event_attrs(observe(name, fixture), expected) - view = {k: v for k, v in got.items() if k not in ("dump", "render_json")} + view = {k: v for k, v in got.items() if k not in ("dump", "dump_unset", "repr", "render_json")} + if "event" in expected: + # A review or citation check on an event: read it by attribute too. + event = parse_webhook(fixture["body"]) + for key, old in expected["event"].items(): + value = getattr(event, key, None) + if isinstance(old, dict) and hasattr(value, "model_dump"): + view["event"][key] = attr_view(value, old) if "dump" in expected: with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) - model = _model_for(name).model_validate(fixture["body"]) + cls = _model_for(name) + model = ( + _extract_via_client(name, fixture["body"]) + if cls is models.ExtractedClaims + else cls.model_validate(fixture["body"]) + ) view["dump"] = attr_view(model, expected["dump"]) returned = expected.get("wait", {}).get("returned") if returned is not None: @@ -181,7 +182,7 @@ def _canonical_names() -> list[str]: @pytest.mark.parametrize("name", _canonical_names()) def test_newer_shape_reads_the_same(name: str) -> None: - expected = {k: v for k, v in _expected(name).items() if k != "render_json"} + expected = {k: v for k, v in _expected(name).items() if k not in ("render_json", "dump_unset", "repr")} got = _canonical_view(name, expected) legacy, canonical = load("legacy", name), load("canonical", name) gaps = [ @@ -194,7 +195,7 @@ def test_every_known_gap_is_still_a_gap() -> None: """A listed gap that closed is stale: drop it, so the list stays exact.""" stale = [] for (name, path), _reason in KNOWN_GAPS.items(): - expected = {k: v for k, v in _expected(name).items() if k != "render_json"} + expected = {k: v for k, v in _expected(name).items() if k not in ("render_json", "dump_unset", "repr")} if path not in {p for p, _, _ in _diff(expected, _canonical_view(name, expected))}: stale.append((name, path)) assert not stale @@ -211,3 +212,35 @@ def test_request_bodies_match_the_previous_release() -> None: from parity_requests import bodies assert bodies() == json.loads((FIXTURES / "requests.json").read_text()) + + +# ── Schemas and pickles ───────────────────────────────────────────────────── + + +def test_model_schemas_match_the_previous_release() -> None: + """Every model the previous release had publishes the same validation and + serialization JSON schema: the newer names are properties, not fields.""" + from parity_static import schemas + + def _shape(schema: Any) -> Any: + # Doc text (class docstrings) may change; the shape may not. + if isinstance(schema, dict): + return {k: _shape(v) for k, v in schema.items() if k != "description"} + if isinstance(schema, list): + return [_shape(v) for v in schema] + return schema + + frozen = _shape(json.loads((FIXTURES / "schemas.json").read_text())) + current = _shape(schemas()) + assert {k: current.get(k) for k in frozen} == frozen + + +def test_objects_pickled_by_the_previous_release_still_dump() -> None: + import base64 + import pickle + + frozen = json.loads((FIXTURES / "pickles.json").read_text()) + assert frozen + for name, blob in frozen.items(): + model = pickle.loads(base64.b64decode(blob)) + assert model.model_dump(mode="json") == _expected(name)["dump"], name diff --git a/tests/test_read_both_shapes.py b/tests/test_read_both_shapes.py index 83eee5c..7212622 100644 --- a/tests/test_read_both_shapes.py +++ b/tests/test_read_both_shapes.py @@ -236,7 +236,9 @@ def test_usage_blocks_are_computed_from_the_pool(name): ) def test_review_new_names_from_both_shapes(name): legacy, canonical = (ReviewFull.model_validate(b) for b in _both(name)) - assert legacy.summary.claim_limit_exceeded == canonical.summary.claim_limit_exceeded + # The original shape says only that the claim limit was REACHED. + assert legacy.summary.claim_limit_exceeded is None + assert canonical.summary.claim_limit_exceeded == bool(canonical.more_claims) assert legacy.summary.citation_limit_exceeded == canonical.summary.citation_limit_exceeded for a, b in zip(legacy.claims, canonical.claims, strict=True): assert a.assessment.more_claims == b.assessment.more_claims @@ -251,14 +253,47 @@ def test_review_failure_code_reads_the_new_spelling(): assert FailureBlock.model_validate({"failure_reason": "not_a_claim"}).code == "no_checkable_claim" -# ── dumps show what was sent ── +# ── the original shape is parsed exactly as before ── -def test_model_dump_shows_the_newer_shape_as_sent(): +def test_newer_shape_dump_keeps_every_key_sent(): canonical = load("canonical", "assess__list_mixed_rows.json")["body"] - assert AssessResponse.model_validate(canonical).model_dump(mode="json") == canonical - canonical = load("canonical", "verify__batch_202.json")["body"] - assert BatchAccepted.model_validate(canonical).model_dump(mode="json") == canonical + dumped = AssessResponse.model_validate(canonical).model_dump(mode="json") + assert set(canonical) <= set(dumped) + assert all(set(row) <= set(d) for row, d in zip(canonical["claims"], dumped["claims"], strict=True)) + + +def test_explicit_null_retryable_is_kept(): + st = TaskStatus.model_validate({"status": "failed", "retryable": None, "failure": {"code": "x", "retryable": True}}) + assert st.retryable is None + assert st.failure is not None and st.failure.retryable is True + + +def test_sparse_usage_dumps_every_default(): + assert set(Usage.model_validate({"plan": "free"}).model_dump()) == set(Usage.model_fields) + + +def test_original_shape_keeps_unset_fields_unset(): + body = {"claim": "x", "verdict": "True", "confidence": "high"} + assert AssessClaim.model_validate(body).model_dump(exclude_unset=True) == body + assert AssessResponse.model_validate({"claims": []}).model_dump(exclude_unset=True) == {"claims": []} + + +def test_new_names_are_properties_not_fields(): + for cls, name in ( + (AssessClaim, "status"), + (AssessClaim, "failure"), + (ExtractedClaims, "claims"), + (TaskStatus, "failure"), + (Verification, "completed_at"), + (FailureBlock, "code"), + ): + assert name not in cls.model_fields + + +def test_model_copy_update_shows_in_the_dump(): + row = AssessClaim.model_validate({"claim": "x", "verdict": "True"}) + assert row.model_copy(update={"verdict": "False"}).model_dump()["verdict"] == "False" # ── webhooks ── @@ -296,6 +331,26 @@ def test_completed_webhook_result_from_both_shapes(): assert legacy.result["modified_at"] == canonical.result["modified_at"] +def test_needs_input_with_a_null_domain_does_not_raise(): + event = parse_webhook( + { + "event": "verification.needs_input", + "task_id": "t", + "needs_input": {"claims": [{"text": "A", "domain": None}]}, + } + ) + assert event.needs_input == {"claims": [{"text": "A", "domain": None}]} + assert [c.claim for c in event.claims] == ["A"] + + +def test_legacy_webhook_event_still_serialises(): + import dataclasses + + event = parse_webhook(load("legacy", "webhook__verification_failed_not_a_claim.json")["body"]) + assert json.loads(json.dumps(dataclasses.asdict(event)))["error"] == "not_a_claim" + assert "failure" not in dataclasses.asdict(event) + + @pytest.mark.parametrize("name", ["webhook__review_completed.json", "webhook__citecheck_completed.json"]) def test_review_webhook_without_task_id(name): canonical = parse_webhook(load("canonical", name)["body"]) @@ -336,10 +391,20 @@ def test_rate_limit_wait_from_both_shapes(): assert (err.retry_after, err.reset_in_seconds) == (0, None) +def test_error_fields_follow_key_presence(): + err = map_response_to_error( + 429, json.dumps({"code": "rate_limited", "reset_in_seconds": None, "retry_after": 30}).encode() + ) + assert err.reset_in_seconds is None + body = {"code": "verification_failed", "hint": "", "failure": {"code": "x", "hint": "from the block"}} + assert map_response_to_error(409, json.dumps(body).encode()).hint == "" + + def test_quota_remaining_is_derived_when_absent(): legacy, canonical = _both("citecheck__402_no_credits.json") assert map_response_to_error(402, json.dumps(canonical).encode()).remaining == 100 assert map_response_to_error(402, json.dumps(legacy).encode()).remaining == 100 + assert map_response_to_error(402, json.dumps({"credits_remaining": 9, "cost": 1}).encode()).remaining is None # ── requests ── From d90b74ba2df6da1c261bbc95a768ae1db5878c86 Mon Sep 17 00:00:00 2001 From: Kosta Date: Thu, 8 Oct 2026 20:27:59 +0300 Subject: [PATCH 5/5] fix(webhooks): a newer-shape review or citecheck event reads its review_id / citecheck_id as task_id Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 5 +++-- src/lenz_io/webhooks.py | 11 +++++++---- tests/test_parity.py | 2 +- tests/test_read_both_shapes.py | 5 ++++- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02166a1..b4108b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,8 +39,9 @@ on upgrade. - Webhooks: an `event_id` property on every event, `VerificationFailed.failure`, `VerificationNeedsInput.reason` and `.claims` (properties: `dataclasses.asdict` and `repr` are unchanged). A review or citation-check - event in the newer shape carries no `task_id` (it reads `""`; deduplicate - on `event_id`, as before). `parse_webhook` and + event in the newer shape carries no `task_id`; it then reads the + `review_id` / `citecheck_id`, so code keyed on `task_id` keeps one key per + review (deduplicate deliveries on `event_id`, as before). `parse_webhook` and `LenzWebhooks.parse` read the newer envelope too (`event`, `event_id`, the work's id, `status`, and the polled body under `verification` / `review` / `citecheck`). diff --git a/src/lenz_io/webhooks.py b/src/lenz_io/webhooks.py index b1141ee..8d6bb54 100644 --- a/src/lenz_io/webhooks.py +++ b/src/lenz_io/webhooks.py @@ -229,7 +229,7 @@ class ReviewEvent(WebhookEvent): Deduplicate on ``event_id``: it is the same on every delivery attempt of one event, while ``attempt`` counts up. ``task_id`` identifies the delivery and cannot be polled on ``/verify/status``; the newer payload - shape leaves it out (it reads ``""``). The deep checks a + shape leaves it out (it then reads ``review_id``). The deep checks a review runs send no ``verification.*`` events of their own. """ @@ -248,7 +248,7 @@ class CitecheckEvent(WebhookEvent): still has it). Deduplicate on ``event_id``: it is the same on every delivery attempt of one event. ``task_id`` identifies the delivery and cannot be polled on ``/verify/status``; the newer payload shape leaves it - out (it reads ``""``). + out (it then reads ``citecheck_id``). """ event_id: str = "" @@ -360,7 +360,9 @@ def _build_event(raw: dict[str, Any]) -> WebhookEvent: review = None return ReviewEvent( event=event, - task_id=task_id, + # The newer payload carries no delivery ``task_id``: the review's + # id stands in, so code keyed on ``task_id`` keeps one key per review. + task_id=task_id if "task_id" in raw else str(payload.get("review_id") or ""), attempt=attempt, delivered_at=delivered_at, verification_id=verification_id, @@ -379,7 +381,8 @@ def _build_event(raw: dict[str, Any]) -> WebhookEvent: check = None return CitecheckEvent( event=event, - task_id=task_id, + # As on a review: the check's id stands in for the missing ``task_id``. + task_id=task_id if "task_id" in raw else str(payload.get("citecheck_id") or ""), attempt=attempt, delivered_at=delivered_at, verification_id=verification_id, diff --git a/tests/test_parity.py b/tests/test_parity.py index ee0b578..b398423 100644 --- a/tests/test_parity.py +++ b/tests/test_parity.py @@ -83,7 +83,7 @@ def _allowed(name: str, path: str, legacy: dict[str, Any], canonical: dict[str, if path == "dump.chain_id" and "chain_id" in lb and "chain_id" not in cb: return "`chain_id` is not in the newer shape" if path == "event.task_id" and "task_id" in lb and "task_id" not in cb: - return "review/citecheck webhooks drop `task_id` (never pollable); dedupe on `event_id`" + return "review/citecheck webhooks drop `task_id` (never pollable); it reads the review or check id" if path.startswith("event.result.") and name.startswith("webhook__verification_completed"): return "`result` is the dict as sent; the newer shape's carries `completed_at`" return KNOWN_GAPS.get((name, path)) diff --git a/tests/test_read_both_shapes.py b/tests/test_read_both_shapes.py index 7212622..a8741bb 100644 --- a/tests/test_read_both_shapes.py +++ b/tests/test_read_both_shapes.py @@ -355,7 +355,10 @@ def test_legacy_webhook_event_still_serialises(): def test_review_webhook_without_task_id(name): canonical = parse_webhook(load("canonical", name)["body"]) assert isinstance(canonical, (ReviewEvent, CitecheckEvent)) - assert canonical.task_id == "" and canonical.event_id != "" + work_id = canonical.review_id if isinstance(canonical, ReviewEvent) else canonical.citecheck_id + assert canonical.task_id == work_id != "" and canonical.event_id != "" + legacy = parse_webhook(load("legacy", name)["body"]) + assert legacy.task_id == load("legacy", name)["body"]["task_id"] # ── errors ──