ruff check src tests scripts
All checks passed!
mypy
Success: no issues found in 79 source files
python3 -m pytest tests/ -v --cov-fail-under=80
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-9.1.1, pluggy-1.6.0 -- /tmp/tracemantle-work/bin/python3
cachedir: .pytest_cache
rootdir: /home/brad/projects/tracemantle
configfile: pyproject.toml
plugins: cov-7.1.0
collecting ... collected 1535 items

tests/test_activation.py::test_clean_phrase_drops_stopwords_and_lowercases PASSED [  0%]
tests/test_activation.py::test_clean_phrase_drops_tokens_under_three_characters PASSED [  0%]
tests/test_activation.py::test_keywords_rank_by_frequency_then_alphabetically PASSED [  0%]
tests/test_activation.py::test_keywords_skip_short_words_and_stopwords PASSED [  0%]
tests/test_activation.py::test_keywords_respect_the_limit PASSED         [  0%]
tests/test_activation.py::test_entropy_is_zero_for_a_single_hypothesis PASSED [  0%]
tests/test_activation.py::test_entropy_is_zero_when_nothing_scored PASSED [  0%]
tests/test_activation.py::test_entropy_is_maximal_for_a_uniform_split PASSED [  0%]
tests/test_activation.py::test_entropy_rises_as_scores_even_out PASSED   [  0%]
tests/test_activation.py::test_dedupe_keeps_first_occurrence_and_drops_case_duplicates PASSED [  0%]
tests/test_activation.py::test_dedupe_drops_empty_phrases PASSED         [  0%]
tests/test_activation.py::test_report_carries_the_skill_name PASSED      [  0%]
tests/test_activation.py::test_hypotheses_are_scored_and_ordered_high_to_low PASSED [  0%]
tests/test_activation.py::test_limit_caps_the_number_of_hypotheses PASSED [  0%]
tests/test_activation.py::test_limit_below_one_is_rejected PASSED        [  0%]
tests/test_activation.py::test_entropy_matches_the_reported_scores PASSED [  1%]
tests/test_activation.py::test_missing_description_still_produces_a_report PASSED [  1%]
tests/test_activation.py::test_text_render_names_the_skill_and_every_phrase PASSED [  1%]
tests/test_activation.py::test_markdown_render_is_a_table_with_one_row_per_hypothesis PASSED [  1%]
tests/test_activation.py::test_json_render_round_trips PASSED            [  1%]
tests/test_activation.py::test_renderers_handle_an_empty_report PASSED   [  1%]
tests/test_adapters.py::test_builtin_adapter_returns_the_records_of_the_pinned_importer PASSED [  1%]
tests/test_adapters.py::test_legacy_promptfoo_import_path_still_resolves PASSED [  1%]
tests/test_adapters.py::test_external_adapter_records_are_stored_under_the_adapter_file_identity PASSED [  1%]
tests/test_adapters.py::test_broken_external_adapter_fails_the_import_without_writing_a_store[VALUE = 1\n-must define adapt] PASSED [  1%]
tests/test_adapters.py::test_broken_external_adapter_fails_the_import_without_writing_a_store[def adapt(export_bytes, bindings):\n    return [{"check_id": "validate"}]\n-must return a list] PASSED [  1%]
tests/test_adapters.py::test_broken_external_adapter_fails_the_import_without_writing_a_store[def adapt(export_bytes, bindings):\n    raise RuntimeError("upstream format changed")\n-RuntimeError: upstream format changed] PASSED [  1%]
tests/test_adapters.py::test_broken_external_adapter_fails_the_import_without_writing_a_store[def adapt(export_bytes, bindings:\n-SyntaxError] PASSED [  1%]
tests/test_adapters.py::test_adapter_inside_the_bundle_is_refused_before_it_runs PASSED [  1%]
tests/test_adapters.py::test_external_adapter_record_for_another_bundle_is_rejected PASSED [  1%]
tests/test_adapters.py::test_external_adapter_cannot_return_unvalidated_evidence PASSED [  2%]
tests/test_agent_prompts.py::test_agents_registry_contains_all_variants PASSED [  2%]
tests/test_agent_prompts.py::test_get_agent_prompt_returns_claude_by_default PASSED [  2%]
tests/test_agent_prompts.py::test_get_agent_prompt_returns_codex PASSED  [  2%]
tests/test_agent_prompts.py::test_get_agent_prompt_returns_cursor PASSED [  2%]
tests/test_agent_prompts.py::test_get_agent_prompt_unknown_raises_value_error PASSED [  2%]
tests/test_agent_prompts.py::test_all_agent_ids_match_registry_keys PASSED [  2%]
tests/test_agent_prompts.py::test_claude_render_contains_xml_skill_tag PASSED [  2%]
tests/test_agent_prompts.py::test_claude_render_contains_xml_schema_tag PASSED [  2%]
tests/test_agent_prompts.py::test_claude_render_contains_worked_example_tag PASSED [  2%]
tests/test_agent_prompts.py::test_claude_render_contains_skill_body PASSED [  2%]
tests/test_agent_prompts.py::test_claude_render_no_markdown_headers PASSED [  2%]
tests/test_agent_prompts.py::test_codex_render_contains_markdown_schema_header PASSED [  2%]
tests/test_agent_prompts.py::test_codex_render_contains_markdown_skill_header PASSED [  2%]
tests/test_agent_prompts.py::test_codex_render_no_xml_tags PASSED        [  2%]
tests/test_agent_prompts.py::test_codex_render_instructs_json_only PASSED [  2%]
tests/test_agent_prompts.py::test_codex_render_contains_skill_body PASSED [  3%]
tests/test_agent_prompts.py::test_cursor_render_contains_skill_body PASSED [  3%]
tests/test_agent_prompts.py::test_cursor_render_no_xml_tags PASSED       [  3%]
tests/test_agent_prompts.py::test_cursor_render_no_markdown_section_headers PASSED [  3%]
tests/test_agent_prompts.py::test_cursor_render_shorter_than_claude PASSED [  3%]
tests/test_agent_prompts.py::test_all_renders_are_deterministic PASSED   [  3%]
tests/test_agent_prompts.py::test_same_agent_different_instances_produce_identical_output PASSED [  3%]
tests/test_agent_prompts.py::test_different_agents_produce_different_output PASSED [  3%]
tests/test_agent_prompts.py::test_worked_example_is_valid_critique_json PASSED [  3%]
tests/test_agent_prompts_smoke.py::test_prompt_digest_matches_snapshot[critique-claude-ClaudePrompt] PASSED [  3%]
tests/test_agent_prompts_smoke.py::test_prompt_digest_matches_snapshot[critique-codex-CodexPrompt] PASSED [  3%]
tests/test_agent_prompts_smoke.py::test_prompt_digest_matches_snapshot[critique-cursor-CursorPrompt] PASSED [  3%]
tests/test_agent_prompts_smoke.py::test_prompt_digest_matches_snapshot[graph-claude-ClaudeGraphPrompt] PASSED [  3%]
tests/test_agent_prompts_smoke.py::test_prompt_digest_matches_snapshot[graph-codex-CodexGraphPrompt] PASSED [  3%]
tests/test_agent_prompts_smoke.py::test_prompt_digest_matches_snapshot[graph-cursor-CursorGraphPrompt] PASSED [  3%]
tests/test_agent_prompts_smoke.py::test_prompt_is_deterministic[critique:claude-ClaudePrompt] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_is_deterministic[critique:codex-CodexPrompt] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_is_deterministic[critique:cursor-CursorPrompt] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_is_deterministic[graph:claude-ClaudeGraphPrompt] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_is_deterministic[graph:codex-CodexGraphPrompt] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_is_deterministic[graph:cursor-CursorGraphPrompt] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_contains_expected_scaffolding_marker[critique:claude-ClaudePrompt-<response_schema>] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_contains_expected_scaffolding_marker[critique:codex-CodexPrompt-## ] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_contains_expected_scaffolding_marker[critique:cursor-CursorPrompt-JSON] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_contains_expected_scaffolding_marker[graph:claude-ClaudeGraphPrompt-<response_schema>] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_contains_expected_scaffolding_marker[graph:codex-CodexGraphPrompt-## ] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_contains_expected_scaffolding_marker[graph:cursor-CursorGraphPrompt-JSON] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_embeds_skill_text[critique:claude-ClaudePrompt] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_embeds_skill_text[critique:codex-CodexPrompt] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_embeds_skill_text[critique:cursor-CursorPrompt] PASSED [  4%]
tests/test_agent_prompts_smoke.py::test_prompt_embeds_skill_text[graph:claude-ClaudeGraphPrompt] PASSED [  5%]
tests/test_agent_prompts_smoke.py::test_prompt_embeds_skill_text[graph:codex-CodexGraphPrompt] PASSED [  5%]
tests/test_agent_prompts_smoke.py::test_prompt_embeds_skill_text[graph:cursor-CursorGraphPrompt] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[model_immutable-False-immutable-False] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[model_immutable-False-immutable-True] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[runner-  UNKNOWN  -incomplete-False] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[runner-  UNKNOWN  -incomplete-True] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[adapter-   -incomplete-False] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[adapter-   -incomplete-True] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[model_revision- Unknown -incomplete-False] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[model_revision- Unknown -incomplete-True] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[environment-value4-incomplete-False] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[environment-value4-incomplete-True] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[environment-value5-incomplete-False] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[environment-value5-incomplete-True] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[tokenizer-value6-incomplete-False] PASSED [  5%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[tokenizer-value6-incomplete-True] PASSED [  6%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[tokenizer-value7-incomplete-False] PASSED [  6%]
tests/test_audit_regressions.py::test_behavioral_reuse_checks_identity_even_for_equal_bundles[tokenizer-value7-incomplete-True] PASSED [  6%]
tests/test_audit_regressions.py::test_compatible_reuse_positive_controls[False-static] PASSED [  6%]
tests/test_audit_regressions.py::test_compatible_reuse_positive_controls[False-behavioral] PASSED [  6%]
tests/test_audit_regressions.py::test_compatible_reuse_positive_controls[True-static] PASSED [  6%]
tests/test_audit_regressions.py::test_compatible_reuse_positive_controls[True-behavioral] PASSED [  6%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[componentResults-None] PASSED [  6%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[componentResults-1] PASSED [  6%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[componentResults-bad] PASSED [  6%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[componentResults-value3] PASSED [  6%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[componentResults-value4] PASSED [  6%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[componentResults-value5] PASSED [  6%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[assertion-None] PASSED [  6%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[assertion-value7] PASSED [  6%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[assertion-1] PASSED [  7%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[assertion-bad] PASSED [  7%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[assertion-value10] PASSED [  7%]
tests/test_audit_regressions.py::test_promptfoo_nested_shapes_fail_with_bound_authentic_rows[assertion-value11] PASSED [  7%]
tests/test_audit_regressions.py::test_auto_discovered_tool_must_be_table[1] PASSED [  7%]
tests/test_audit_regressions.py::test_auto_discovered_tool_must_be_table[[]] PASSED [  7%]
tests/test_audit_regressions.py::test_auto_discovered_tool_must_be_table["tracemantle"] PASSED [  7%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[json-2026-09-12] PASSED [  7%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[json-2026-09-12T12:00:00Z] PASSED [  7%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[json-[text]] PASSED [  7%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[json-{key: text}] PASSED [  7%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[json-true] PASSED [  7%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[json-42] PASSED [  7%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[text-2026-09-12] PASSED [  7%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[text-2026-09-12T12:00:00Z] PASSED [  7%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[text-[text]] PASSED [  8%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[text-{key: text}] PASSED [  8%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[text-true] PASSED [  8%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[text-42] PASSED [  8%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[github-2026-09-12] PASSED [  8%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[github-2026-09-12T12:00:00Z] PASSED [  8%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[github-[text]] PASSED [  8%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[github-{key: text}] PASSED [  8%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[github-true] PASSED [  8%]
tests/test_audit_regressions.py::test_manifest_invalid_description_is_domain_error[github-42] PASSED [  8%]
tests/test_audit_regressions.py::test_history_paths_escape_controls[missing-False] PASSED [  8%]
tests/test_audit_regressions.py::test_history_paths_escape_controls[missing-True] PASSED [  8%]
tests/test_audit_regressions.py::test_history_paths_escape_controls[empty-store-False] PASSED [  8%]
tests/test_audit_regressions.py::test_history_paths_escape_controls[empty-store-True] PASSED [  8%]
tests/test_audit_regressions.py::test_history_paths_escape_controls[multiple-False] PASSED [  8%]
tests/test_audit_regressions.py::test_history_paths_escape_controls[multiple-True] PASSED [  8%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[`[label](missing.md)`] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[``[label](missing.md)``] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[`` `[label](missing.md)` ``] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[`[label](scripts/missing.md)`] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[`[label/path]`] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[`include:scripts/missing.md`] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[`![label](missing.png)`] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[`<a href="missing.md">`] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[`include: missing.md`] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[`[label]: missing.md`\n[label]] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[    [label](missing.md)] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[\t[label](missing.md)] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[    [label]: missing.md\n\n[label]] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[    <img src="missing.png">] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[    include: missing.md] PASSED [  9%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[```md\n[label](missing.md)\n```] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[~~~~\n[label](missing.md)\n~~~~] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_code_examples_are_not_dependencies[``multi\n[label](missing.md)\nline``] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[`scripts/helper.py`-scripts/helper.py-resource-8] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[`assets(v1)/helper.py`-assets(v1)/helper.py-resource-8] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[`scripts/helper[old].py`-scripts/helper[old].py-resource-8] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[``scripts/helper.py``-scripts/helper.py-resource-8] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[`report.json`-report.json-generated-8] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[`example` [real](actual.md)-actual.md-link-8] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[`` a ` b ``\n[real](actual.md)-actual.md-link-9] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[`unclosed [real](actual.md)-actual.md-link-8] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[`unclosed\n\n[real](actual.md) `-actual.md-link-10] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[`unclosed\n```\nexample\n```\n[real](actual.md) `-actual.md-link-12] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[[label]: actual.md\n[label]-actual.md-link-8] PASSED [ 10%]
tests/test_audit_regressions.py::test_markdown_real_resources_keep_locations[    [example](missing.md)\n\n[real](actual.md)-actual.md-link-10] PASSED [ 10%]
tests/test_audit_regressions.py::test_conflicting_approved_records_cannot_hide_nonpassing_state[fail-fail-1] PASSED [ 11%]
tests/test_audit_regressions.py::test_conflicting_approved_records_cannot_hide_nonpassing_state[unknown-unknown-4] PASSED [ 11%]
tests/test_audit_regressions.py::test_conflicting_approved_records_cannot_hide_nonpassing_state[skipped-unknown-4] PASSED [ 11%]
tests/test_audit_regressions.py::test_conflicting_approved_records_cannot_hide_nonpassing_state[infrastructure-error-infrastructure-error-2] PASSED [ 11%]
tests/test_audit_regressions.py::test_nonpublishing_workflow_preserves_real_release_dependency PASSED [ 11%]
tests/test_audit_regressions.py::test_history_missing_after_discovery_escapes_path PASSED [ 11%]
tests/test_audit_regressions.py::test_markdown_code_contexts_through_cli_and_manifest PASSED [ 11%]
tests/test_audit_regressions.py::test_incompatible_approved_behavioral_evidence_blocks_real_cli[False-alias] PASSED [ 11%]
tests/test_audit_regressions.py::test_incompatible_approved_behavioral_evidence_blocks_real_cli[False-environment] PASSED [ 11%]
tests/test_audit_regressions.py::test_incompatible_approved_behavioral_evidence_blocks_real_cli[False-tokenizer] PASSED [ 11%]
tests/test_audit_regressions.py::test_incompatible_approved_behavioral_evidence_blocks_real_cli[True-alias] PASSED [ 11%]
tests/test_audit_regressions.py::test_incompatible_approved_behavioral_evidence_blocks_real_cli[True-environment] PASSED [ 11%]
tests/test_audit_regressions.py::test_incompatible_approved_behavioral_evidence_blocks_real_cli[True-tokenizer] PASSED [ 11%]
tests/test_audit_regressions.py::test_malformed_trusted_check_kind_is_domain_error PASSED [ 11%]
tests/test_audit_regressions.py::test_yaml_scalar_conversion_errors_are_bounded_and_batch_continues[invalid-month] PASSED [ 11%]
tests/test_audit_regressions.py::test_yaml_scalar_conversion_errors_are_bounded_and_batch_continues[invalid-hour] PASSED [ 11%]
tests/test_audit_regressions.py::test_yaml_scalar_conversion_errors_are_bounded_and_batch_continues[invalid-timezone] PASSED [ 12%]
tests/test_audit_regressions.py::test_yaml_scalar_conversion_errors_are_bounded_and_batch_continues[integer-conversion-limit] PASSED [ 12%]
tests/test_automation_approvals.py::test_automation_pass_and_disabled_authority_restore_digest_requirement PASSED [ 12%]
tests/test_automation_approvals.py::test_wrong_signed_subject_or_run_fails_closed[evidence_sha256-0000000000000000000000000000000000000000000000000000000000000000] PASSED [ 12%]
tests/test_automation_approvals.py::test_wrong_signed_subject_or_run_fails_closed[bundle_sha256-0000000000000000000000000000000000000000000000000000000000000000] PASSED [ 12%]
tests/test_automation_approvals.py::test_wrong_signed_subject_or_run_fails_closed[policy_sha256-0000000000000000000000000000000000000000000000000000000000000000] PASSED [ 12%]
tests/test_automation_approvals.py::test_wrong_signed_subject_or_run_fails_closed[trusted_revision-0000000000000000000000000000000000000000] PASSED [ 12%]
tests/test_automation_approvals.py::test_wrong_signed_subject_or_run_fails_closed[check_id-different] PASSED [ 12%]
tests/test_automation_approvals.py::test_wrong_signed_subject_or_run_fails_closed[run_id-other-run] PASSED [ 12%]
tests/test_automation_approvals.py::test_wrong_signed_subject_or_run_fails_closed[run_started_at-2000-01-01T00:00:00Z] PASSED [ 12%]
tests/test_automation_approvals.py::test_wrong_signed_subject_or_run_fails_closed[schema_version-True] PASSED [ 12%]
tests/test_automation_approvals.py::test_wrong_signed_subject_or_run_fails_closed[kind-check-evidence] PASSED [ 12%]
tests/test_automation_approvals.py::test_wrong_signed_subject_or_run_fails_closed[extra-unsupported] PASSED [ 12%]
tests/test_automation_approvals.py::test_approval_lifetime_and_independent_run_context[expired] PASSED [ 12%]
tests/test_automation_approvals.py::test_approval_lifetime_and_independent_run_context[future] PASSED [ 12%]
tests/test_automation_approvals.py::test_approval_lifetime_and_independent_run_context[too-long] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_lifetime_and_independent_run_context[before-start] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_lifetime_and_independent_run_context[replayed] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_lifetime_and_independent_run_context[missing-context] PASSED [ 13%]
tests/test_automation_approvals.py::test_wrong_key_altered_record_and_missing_signature PASSED [ 13%]
tests/test_automation_approvals.py::test_revocation_and_missing_verifier PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[state-unknown] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[state-skipped] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[state-fail] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[observation_method-model-judgment] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[model_immutable-False] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[checker_sha256-0000000000000000000000000000000000000000000000000000000000000000] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[configuration_sha256-0000000000000000000000000000000000000000000000000000000000000000] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[profile_sha256-0000000000000000000000000000000000000000000000000000000000000000] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[fixture_sha256-0000000000000000000000000000000000000000000000000000000000000000] PASSED [ 13%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[permissions-value9] PASSED [ 14%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[environment-value10] PASSED [ 14%]
tests/test_automation_approvals.py::test_approval_does_not_relax_evidence_compatibility[adapter-unknown] PASSED [ 14%]
tests/test_automation_approvals.py::test_missing_conflicting_and_helper_changed_records_cannot_pass PASSED [ 14%]
tests/test_automation_approvals.py::test_candidate_policy_checker_adapter_and_trust_worktree_cannot_choose_authority PASSED [ 14%]
tests/test_automation_approvals.py::test_invalid_authority_configuration_fails_closed[version] PASSED [ 14%]
tests/test_automation_approvals.py::test_invalid_authority_configuration_fails_closed[empty-keys] PASSED [ 14%]
tests/test_automation_approvals.py::test_invalid_authority_configuration_fails_closed[bad-key] PASSED [ 14%]
tests/test_automation_approvals.py::test_invalid_authority_configuration_fails_closed[unknown-check] PASSED [ 14%]
tests/test_automation_approvals.py::test_invalid_authority_configuration_fails_closed[age] PASSED [ 14%]
tests/test_automation_approvals.py::test_invalid_authority_configuration_fails_closed[extra] PASSED [ 14%]
tests/test_automation_approvals.py::test_invalid_authority_configuration_fails_closed[schema1] PASSED [ 14%]
tests/test_automation_approvals.py::test_malformed_or_oversized_approval[{"schema_version":1,"schema_version":1}] PASSED [ 14%]
tests/test_automation_approvals.py::test_malformed_or_oversized_approval[{"x":1e999}] PASSED [ 14%]
tests/test_automation_approvals.py::test_malformed_or_oversized_approval[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] PASSED [ 14%]
tests/test_automation_approvals.py::test_required_record_signatures_still_apply_to_automation PASSED [ 14%]
tests/test_automation_approvals.py::test_producer_two_changed_bundles_no_digest_commits_and_secret_isolation PASSED [ 15%]
tests/test_batch15_summarize.py::test_severity_counts_reads_nested_cli_results PASSED [ 15%]
tests/test_batch15_summarize.py::test_missing_json_report_is_not_counted_as_zero PASSED [ 15%]
tests/test_batch15_summarize.py::test_collect_rows_marks_missing_phase_b_as_pending PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_graph_report_history_parses_source_once PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_manifest_reuses_source_parse PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_cold_offline_tokenizer_is_explicit PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_emit_batch_continues_after_malformed_source[--emit-graph] PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_emit_batch_continues_after_malformed_source[--emit-critique-prompt] PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_emit_batch_continues_after_malformed_source[--emit-graph-prompt] PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_emit_batch_continues_after_malformed_source[--agent-reason] PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_emit_batch_continues_after_malformed_source[--activation-hypotheses] PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_malformed_history_blocks_final_gate[bundle_sha256] PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_malformed_history_blocks_final_gate[configuration_sha256] PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_malformed_history_blocks_final_gate[entry] PASSED [ 15%]
tests/test_build_plan_acceptance.py::test_namespaced_alias_precedence_and_ambiguity PASSED [ 16%]
tests/test_build_plan_acceptance.py::test_unknown_execution_identity_cannot_pass_even_when_approved PASSED [ 16%]
tests/test_build_plan_acceptance.py::test_graph_budget_rejects_without_traceback PASSED [ 16%]
tests/test_build_plan_acceptance.py::test_incomparable_configuration_does_not_reuse_history PASSED [ 16%]
tests/test_build_plan_acceptance.py::test_alias_expansion_is_bounded_in_real_process PASSED [ 16%]
tests/test_build_plan_acceptance.py::test_cross_branch_dependency_cycle_is_detected PASSED [ 16%]
tests/test_build_plan_core.py::test_malformed_yaml_is_rejected[duplicate-name] PASSED [ 16%]
tests/test_build_plan_core.py::test_malformed_yaml_is_rejected[duplicate-nested] PASSED [ 16%]
tests/test_build_plan_core.py::test_malformed_yaml_is_rejected[inline-close] PASSED [ 16%]
tests/test_build_plan_core.py::test_malformed_yaml_is_rejected[nonstring-key] PASSED [ 16%]
tests/test_build_plan_core.py::test_malformed_yaml_is_rejected[boolean-key] PASSED [ 16%]
tests/test_build_plan_core.py::test_malformed_yaml_is_rejected[mapping-key] PASSED [ 16%]
tests/test_build_plan_core.py::test_malformed_yaml_is_rejected[recursive-alias] PASSED [ 16%]
tests/test_build_plan_core.py::test_valid_yaml_boundaries[valid-standard] PASSED [ 16%]
tests/test_build_plan_core.py::test_valid_yaml_boundaries[valid-multiline] PASSED [ 16%]
tests/test_build_plan_core.py::test_valid_yaml_boundaries[valid-empty-block] PASSED [ 17%]
tests/test_build_plan_core.py::test_valid_yaml_boundaries[valid-bom] PASSED [ 17%]
tests/test_build_plan_core.py::test_valid_yaml_boundaries[valid-crlf] PASSED [ 17%]
tests/test_build_plan_core.py::test_valid_yaml_boundaries[valid-alias] PASSED [ 17%]
tests/test_build_plan_core.py::test_parsed_document_is_deeply_immutable PASSED [ 17%]
tests/test_build_plan_core.py::test_standard_field_validation[bad-metadata-frontmatter.metadata.type] PASSED [ 17%]
tests/test_build_plan_core.py::test_standard_field_validation[bad-metadata-values-frontmatter.metadata.type] PASSED [ 17%]
tests/test_build_plan_core.py::test_standard_field_validation[bad-compatibility-frontmatter.compatibility.type] PASSED [ 17%]
tests/test_build_plan_core.py::test_standard_fields_are_not_vendor_or_unknown PASSED [ 17%]
tests/test_build_plan_core.py::test_examples_and_external_schemes_are_not_local_dependencies[fenced-links] PASSED [ 17%]
tests/test_build_plan_core.py::test_examples_and_external_schemes_are_not_local_dependencies[external-links] PASSED [ 17%]
tests/test_build_plan_core.py::test_actual_dependency_chains_and_cycles PASSED [ 17%]
tests/test_build_plan_core.py::test_read_cap_is_enforced_on_actual_bytes PASSED [ 17%]
tests/test_build_plan_core.py::test_deep_yaml_is_bounded PASSED          [ 17%]
tests/test_build_plan_core.py::test_evidence_json_rejects_ambiguous_and_deep_inputs[{"x": 1, "x": 2}] PASSED [ 17%]
tests/test_build_plan_core.py::test_evidence_json_rejects_ambiguous_and_deep_inputs[{"x": NaN}] PASSED [ 17%]
tests/test_build_plan_core.py::test_evidence_json_rejects_ambiguous_and_deep_inputs[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[0]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] PASSED [ 18%]
tests/test_build_plan_core.py::test_controls_are_escaped_only_for_display PASSED [ 18%]
tests/test_build_plan_core.py::test_config_precedence_and_no_global_state PASSED [ 18%]
tests/test_build_plan_core.py::test_explicit_default_cli_values_win PASSED [ 18%]
tests/test_build_plan_core.py::test_duplicate_toml_is_rejected PASSED    [ 18%]
tests/test_build_plan_core.py::test_batch_json_is_one_document[--emit-graph] PASSED [ 18%]
tests/test_build_plan_core.py::test_batch_json_is_one_document[--emit-critique-prompt] PASSED [ 18%]
tests/test_build_plan_core.py::test_batch_json_is_one_document[--emit-graph-prompt] PASSED [ 18%]
tests/test_build_plan_core.py::test_batch_json_is_one_document[--activation-hypotheses] PASSED [ 18%]
tests/test_build_plan_core.py::test_batch_json_is_one_document[--agent-reason] PASSED [ 18%]
tests/test_build_plan_core.py::test_batch_json_is_one_document[--analyze-graph] PASSED [ 18%]
tests/test_build_plan_core.py::test_duplicate_paths_are_resolved_once_and_graph_ignore_controls_gate PASSED [ 18%]
tests/test_build_plan_core.py::test_explicit_tokenizer_provenance_and_special_markers PASSED [ 18%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[changed-permission] PASSED [ 18%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[control] PASSED [ 18%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[description-change] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[failed] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[future] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[helper-change] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[incomplete] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[inferred] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[infrastructure] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[missing-evidence] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[model-alias] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[model-judgment] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[skipped] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[stale] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[untrusted] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[wrong-bundle] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[wrong-checker] PASSED [ 19%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[wrong-config] PASSED [ 20%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[wrong-fixture] PASSED [ 20%]
tests/test_build_plan_product.py::test_conservative_comparison_scenarios[wrong-profile] PASSED [ 20%]
tests/test_build_plan_product.py::test_manifest_helper_identity_and_reproducibility PASSED [ 20%]
tests/test_build_plan_product.py::test_ambiguous_manifest_paths_are_rejected[/absolute] PASSED [ 20%]
tests/test_build_plan_product.py::test_ambiguous_manifest_paths_are_rejected[../escape] PASSED [ 20%]
tests/test_build_plan_product.py::test_ambiguous_manifest_paths_are_rejected[a//b] PASSED [ 20%]
tests/test_build_plan_product.py::test_ambiguous_manifest_paths_are_rejected[a/./b] PASSED [ 20%]
tests/test_build_plan_product.py::test_ambiguous_manifest_paths_are_rejected[a\\b] PASSED [ 20%]
tests/test_build_plan_product.py::test_ambiguous_manifest_paths_are_rejected[C:drive] PASSED [ 20%]
tests/test_build_plan_product.py::test_ambiguous_manifest_paths_are_rejected[a\x1b.md] PASSED [ 20%]
tests/test_build_plan_product.py::test_ambiguous_manifest_paths_are_rejected[cafe\u0301.md] PASSED [ 20%]
tests/test_build_plan_product.py::test_manifest_does_not_follow_symlinks PASSED [ 20%]
tests/test_build_plan_product.py::test_evidence_rejects_incomplete_and_coerced_identity[schema_version-True] PASSED [ 20%]
tests/test_build_plan_product.py::test_evidence_rejects_incomplete_and_coerced_identity[state-success] PASSED [ 20%]
tests/test_build_plan_product.py::test_evidence_rejects_incomplete_and_coerced_identity[bundle_sha256-short] PASSED [ 20%]
tests/test_build_plan_product.py::test_evidence_rejects_incomplete_and_coerced_identity[model_immutable-false] PASSED [ 21%]
tests/test_build_plan_product.py::test_evidence_rejects_incomplete_and_coerced_identity[observed_at-yesterday] PASSED [ 21%]
tests/test_build_plan_product.py::test_evidence_rejects_incomplete_and_coerced_identity[permissions-value5] PASSED [ 21%]
tests/test_build_plan_product.py::test_evidence_rejects_incomplete_and_coerced_identity[environment-value6] PASSED [ 21%]
tests/test_build_plan_product.py::test_evidence_rejects_incomplete_and_coerced_identity[inputs-value7] PASSED [ 21%]
tests/test_build_plan_product.py::test_evidence_rejects_incomplete_and_coerced_identity[tokenizer-value8] PASSED [ 21%]
tests/test_build_plan_product.py::test_evidence_rejects_incomplete_and_coerced_identity[runner-] PASSED [ 21%]
tests/test_build_plan_product.py::test_promptfoo_authentic_fixture_is_version_pinned_and_does_not_claim_invocation PASSED [ 21%]
tests/test_build_plan_product.py::test_promptfoo_malformed_rows_are_rejected[success-false] PASSED [ 21%]
tests/test_build_plan_product.py::test_promptfoo_malformed_rows_are_rejected[success-1] PASSED [ 21%]
tests/test_build_plan_product.py::test_promptfoo_malformed_rows_are_rejected[testCase-value2] PASSED [ 21%]
tests/test_build_plan_product.py::test_promptfoo_malformed_rows_are_rejected[provider-claimed] PASSED [ 21%]
tests/test_build_plan_product.py::test_promptfoo_malformed_rows_are_rejected[gradingResult-value4] PASSED [ 21%]
tests/test_build_plan_product.py::test_legacy_history_fields_are_strict[result-valid-false] PASSED [ 21%]
tests/test_build_plan_product.py::test_legacy_history_fields_are_strict[result-error-True] PASSED [ 21%]
tests/test_build_plan_product.py::test_legacy_history_fields_are_strict[validation_modes-symbolic-false] PASSED [ 22%]
tests/test_build_plan_product.py::test_legacy_history_fields_are_strict[result-info--1] PASSED [ 22%]
tests/test_build_plan_product.py::test_legacy_history_fields_are_strict[agents-graph_agent-1] PASSED [ 22%]
tests/test_build_plan_product.py::test_migration_is_explicit_idempotent_and_preserves_source PASSED [ 22%]
tests/test_build_plan_product.py::test_concurrent_immutable_writers_preserve_records PASSED [ 22%]
tests/test_build_plan_product.py::test_cli_trusted_base_cannot_be_weakened_by_candidate PASSED [ 22%]
tests/test_build_plan_product.py::test_product_cli_manifest_import_migration_and_annotations PASSED [ 22%]
tests/test_changelog_release_check.py::test_promoted_version_with_empty_unreleased_passes PASSED [ 22%]
tests/test_changelog_release_check.py::test_unpromoted_entries_with_no_version_heading_pass PASSED [ 22%]
tests/test_changelog_release_check.py::test_version_heading_plus_leftover_unreleased_entries_fail PASSED [ 22%]
tests/test_changelog_release_check.py::test_no_version_heading_and_empty_unreleased_fails PASSED [ 22%]
tests/test_changelog_release_check.py::test_missing_unreleased_section_is_treated_as_empty PASSED [ 22%]
tests/test_changelog_release_check.py::test_heading_match_is_exact_not_prefix PASSED [ 22%]
tests/test_changelog_release_check.py::test_main_rejects_a_version_that_is_not_a_version PASSED [ 22%]
tests/test_changelog_release_check.py::test_released_version_with_pending_next_entries_passes PASSED [ 22%]
tests/test_cli.py::test_valid_file_exits_zero PASSED                     [ 22%]
tests/test_cli.py::test_invalid_file_exits_one PASSED                    [ 23%]
tests/test_cli.py::test_missing_file_exits_two PASSED                    [ 23%]
tests/test_cli.py::test_empty_directory_exits_two PASSED                 [ 23%]
tests/test_cli.py::test_text_output_is_default PASSED                    [ 23%]
tests/test_cli.py::test_text_output_shows_fail_for_invalid_file PASSED   [ 23%]
tests/test_cli.py::test_text_output_shows_rule_id_and_message PASSED     [ 23%]
tests/test_cli.py::test_text_output_includes_summary_line PASSED         [ 23%]
tests/test_cli.py::test_json_output_is_valid_json PASSED                 [ 23%]
tests/test_cli.py::test_json_output_schema_for_valid_file PASSED         [ 23%]
tests/test_cli.py::test_json_output_schema_for_invalid_file PASSED       [ 23%]
tests/test_cli.py::test_directory_mode_finds_skill_files PASSED          [ 23%]
tests/test_cli.py::test_directory_mode_ignores_non_skill_md_files PASSED [ 23%]
tests/test_cli.py::test_max_lines_override_triggers_warning PASSED       [ 23%]
tests/test_cli.py::test_max_lines_override_with_strict_exits_one PASSED  [ 23%]
tests/test_cli.py::test_max_tokens_override_triggers_warning PASSED      [ 23%]
tests/test_cli.py::test_ignore_prefix_suppresses_matching_rules PASSED   [ 24%]
tests/test_cli.py::test_ignore_prefix_does_not_suppress_unrelated_rules PASSED [ 24%]
tests/test_cli.py::test_version_flag_shows_version PASSED                [ 24%]
tests/test_cli.py::test_pass_shows_checkmark_symbol PASSED               [ 24%]
tests/test_cli.py::test_fail_shows_cross_symbol PASSED                   [ 24%]
tests/test_cli.py::test_warning_severity_shown_in_diagnostics PASSED     [ 24%]
tests/test_cli.py::test_summary_includes_warning_count PASSED            [ 24%]
tests/test_cli.py::test_no_color_flag_accepted PASSED                    [ 24%]
tests/test_cli.py::test_help_shows_examples PASSED                       [ 24%]
tests/test_cli.py::test_quiet_flag_suppresses_output_valid PASSED        [ 24%]
tests/test_cli.py::test_quiet_flag_short_form PASSED                     [ 24%]
tests/test_cli.py::test_quiet_flag_still_fails_with_exit_code PASSED     [ 24%]
tests/test_cli.py::test_quiet_flag_with_json_format PASSED               [ 24%]
tests/test_cli.py::test_strict_cursor_fails_on_folded_keep PASSED        [ 24%]
tests/test_cli.py::test_strict_cursor_passes_on_folded_strip PASSED      [ 24%]
tests/test_cli.py::test_target_agent_cursor_accepted PASSED              [ 25%]
tests/test_cli.py::test_strict_escalates_warning_run_to_exit_one PASSED  [ 25%]
tests/test_cli.py::test_strict_promotes_cursor_block_scalar_to_error PASSED [ 25%]
tests/test_cli.py::test_strict_passes_on_clean_skill PASSED              [ 25%]
tests/test_cli.py::test_modes_exit_clean_on_non_utf8_file[--emit-graph] PASSED [ 25%]
tests/test_cli.py::test_modes_exit_clean_on_non_utf8_file[--emit-critique-prompt] PASSED [ 25%]
tests/test_cli.py::test_modes_exit_clean_on_non_utf8_file[--emit-graph-prompt] PASSED [ 25%]
tests/test_cli.py::test_modes_exit_clean_on_non_utf8_file[--agent-reason] PASSED [ 25%]
tests/test_cli.py::test_modes_exit_clean_on_non_utf8_file[--activation-hypotheses] PASSED [ 25%]
tests/test_cli.py::test_modes_exit_clean_on_non_utf8_file[--analyze-graph] PASSED [ 25%]
tests/test_cli.py::test_modes_exit_clean_on_non_utf8_file[--history] PASSED [ 25%]
tests/test_cli.py::test_ingest_critique_non_utf8_response_exits_two PASSED [ 25%]
tests/test_cli.py::test_ingest_response_over_size_cap_exits_two PASSED   [ 25%]
tests/test_cli.py::test_collect_paths_does_not_follow_directory_symlinks PASSED [ 25%]
tests/test_cli_critique.py::test_emit_critique_prompt_exits_zero PASSED  [ 25%]
tests/test_cli_critique.py::test_emit_critique_prompt_stdout_contains_prompt PASSED [ 25%]
tests/test_cli_critique.py::test_emit_critique_prompt_stderr_empty PASSED [ 26%]
tests/test_cli_critique.py::test_emit_critique_prompt_no_symbolic_output PASSED [ 26%]
tests/test_cli_critique.py::test_emit_critique_prompt_contains_skill_content PASSED [ 26%]
tests/test_cli_critique.py::test_emit_critique_prompt_json_format_is_valid_json PASSED [ 26%]
tests/test_cli_critique.py::test_emit_critique_prompt_json_prompt_key_is_string PASSED [ 26%]
tests/test_cli_critique.py::test_emit_critique_prompt_directory_contains_delimiters PASSED [ 26%]
tests/test_cli_critique.py::test_emit_critique_prompt_single_file_no_delimiter PASSED [ 26%]
tests/test_cli_critique.py::test_ingest_critique_rejects_multiple_paths PASSED [ 26%]
tests/test_cli_critique.py::test_ingest_critique_clean_passing_skill_exits_zero PASSED [ 26%]
tests/test_cli_critique.py::test_ingest_critique_clean_passing_skill_produces_report PASSED [ 26%]
tests/test_cli_critique.py::test_ingest_critique_contradiction_on_passing_skill_exits_three PASSED [ 26%]
tests/test_cli_critique.py::test_ingest_critique_contradiction_report_shows_contradiction PASSED [ 26%]
tests/test_cli_critique.py::test_ingest_critique_contradiction_on_failing_skill_exits_one PASSED [ 26%]
tests/test_cli_critique.py::test_ingest_critique_failing_skill_report_shows_both_issues PASSED [ 26%]
tests/test_cli_critique.py::test_ingest_critique_malformed_json_exits_one PASSED [ 26%]
tests/test_cli_critique.py::test_ingest_critique_malformed_json_emits_ingest_error_rule PASSED [ 27%]
tests/test_cli_critique.py::test_ingest_critique_schema_error_exits_one PASSED [ 27%]
tests/test_cli_critique.py::test_ingest_critique_schema_error_emits_ingest_rule PASSED [ 27%]
tests/test_cli_critique.py::test_ingest_critique_missing_path_exits_two PASSED [ 27%]
tests/test_cli_critique.py::test_ingest_critique_missing_path_message_names_path PASSED [ 27%]
tests/test_cli_critique.py::test_ingest_critique_stdin_clean_exits_zero PASSED [ 27%]
tests/test_cli_critique.py::test_ingest_critique_stdin_contradiction_exits_three PASSED [ 27%]
tests/test_cli_critique.py::test_both_flags_together_exits_two PASSED    [ 27%]
tests/test_cli_critique.py::test_both_flags_together_message_names_both_flags PASSED [ 27%]
tests/test_cli_critique.py::test_regression_valid_skill_text_format PASSED [ 27%]
tests/test_cli_critique.py::test_regression_invalid_skill_exits_one PASSED [ 27%]
tests/test_cli_critique.py::test_regression_json_format PASSED           [ 27%]
tests/test_cli_critique.py::test_regression_ignore_flag PASSED           [ 27%]
tests/test_cli_critique.py::test_regression_target_agent_vscode PASSED   [ 27%]
tests/test_cli_critique_agent.py::test_emit_claude_contains_xml_skill_tag PASSED [ 27%]
tests/test_cli_critique_agent.py::test_emit_codex_contains_markdown_skill_header PASSED [ 28%]
tests/test_cli_critique_agent.py::test_emit_codex_no_xml_tags PASSED     [ 28%]
tests/test_cli_critique_agent.py::test_emit_cursor_shorter_than_claude PASSED [ 28%]
tests/test_cli_critique_agent.py::test_emit_default_equals_claude PASSED [ 28%]
tests/test_cli_critique_agent.py::test_ingest_text_output_has_critique_source PASSED [ 28%]
tests/test_cli_critique_agent.py::test_ingest_json_output_has_critique_source_field PASSED [ 28%]
tests/test_cli_critique_agent.py::test_ingest_default_agent_adds_claude_source PASSED [ 28%]
tests/test_cli_critique_agent.py::test_ingest_json_default_agent_adds_claude_source_field PASSED [ 28%]
tests/test_cli_critique_agent.py::test_critique_agent_without_emit_or_ingest_exits_two PASSED [ 28%]
tests/test_cli_critique_agent.py::test_invalid_agent_name_exits_two PASSED [ 28%]
tests/test_cli_critique_agent.py::test_emit_without_critique_agent_exits_zero PASSED [ 28%]
tests/test_cli_critique_agent.py::test_ingest_without_critique_agent_exits_zero PASSED [ 28%]
tests/test_cli_graph.py::test_emit_graph_exits_zero PASSED               [ 28%]
tests/test_cli_graph.py::test_emit_graph_text_contains_source PASSED     [ 28%]
tests/test_cli_graph.py::test_emit_graph_text_contains_sections PASSED   [ 28%]
tests/test_cli_graph.py::test_emit_graph_text_contains_capability_name PASSED [ 28%]
tests/test_cli_graph.py::test_emit_graph_text_contains_io_items PASSED   [ 29%]
tests/test_cli_graph.py::test_emit_graph_produces_no_validation_report PASSED [ 29%]
tests/test_cli_graph.py::test_emit_graph_json_exits_zero PASSED          [ 29%]
tests/test_cli_graph.py::test_emit_graph_json_is_valid_json PASSED       [ 29%]
tests/test_cli_graph.py::test_emit_graph_json_has_expected_keys PASSED   [ 29%]
tests/test_cli_graph.py::test_emit_graph_json_capability_count PASSED    [ 29%]
tests/test_cli_graph.py::test_emit_graph_directory_emits_delimiter PASSED [ 29%]
tests/test_cli_graph.py::test_analyze_graph_exits_zero_for_clean_file PASSED [ 29%]
tests/test_cli_graph.py::test_analyze_graph_exits_zero_when_only_warnings PASSED [ 29%]
tests/test_cli_graph.py::test_analyze_graph_includes_graph_rule_in_output PASSED [ 29%]
tests/test_cli_graph.py::test_analyze_graph_still_includes_validation_summary PASSED [ 29%]
tests/test_cli_graph.py::test_analyze_graph_json_includes_graph_diagnostics PASSED [ 29%]
tests/test_cli_graph.py::test_analyze_graph_no_graph_diagnostics_for_empty_graph PASSED [ 29%]
tests/test_cli_graph.py::test_emit_graph_and_analyze_graph_are_mutually_exclusive PASSED [ 29%]
tests/test_cli_graph.py::test_emit_graph_and_emit_critique_prompt_are_mutually_exclusive PASSED [ 29%]
tests/test_cli_graph.py::test_emit_graph_and_ingest_critique_are_mutually_exclusive PASSED [ 30%]
tests/test_cli_graph.py::test_normal_validation_unaffected_by_new_flags PASSED [ 30%]
tests/test_cli_graph.py::test_format_json_still_works_without_graph_flags PASSED [ 30%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_claude_contains_xml_skill_tag PASSED [ 30%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_codex_contains_markdown_skill_header PASSED [ 30%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_codex_no_xml_tags PASSED [ 30%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_cursor_shorter_than_claude PASSED [ 30%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_default_equals_claude PASSED [ 30%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_exits_0 PASSED     [ 30%]
tests/test_cli_graph_agent.py::test_ingest_graph_clean_exits_0 PASSED    [ 30%]
tests/test_cli_graph_agent.py::test_ingest_graph_text_report_has_graph_source_header PASSED [ 30%]
tests/test_cli_graph_agent.py::test_ingest_graph_json_report_has_graph_source_field PASSED [ 30%]
tests/test_cli_graph_agent.py::test_ingest_graph_explicit_codex_agent_shows_in_header PASSED [ 30%]
tests/test_cli_graph_agent.py::test_ingest_graph_contradiction_exits_1 PASSED [ 30%]
tests/test_cli_graph_agent.py::test_ingest_graph_contradiction_has_error_diagnostic PASSED [ 30%]
tests/test_cli_graph_agent.py::test_ingest_graph_malformed_json_exits_1 PASSED [ 31%]
tests/test_cli_graph_agent.py::test_ingest_graph_schema_error_exits_1 PASSED [ 31%]
tests/test_cli_graph_agent.py::test_ingest_graph_parse_error_has_semantic_diagnostic PASSED [ 31%]
tests/test_cli_graph_agent.py::test_analyze_graph_shows_heuristic_source_text PASSED [ 31%]
tests/test_cli_graph_agent.py::test_analyze_graph_shows_heuristic_source_json PASSED [ 31%]
tests/test_cli_graph_agent.py::test_ingest_graph_and_ingest_critique_together_exits_0 PASSED [ 31%]
tests/test_cli_graph_agent.py::test_ingest_graph_and_ingest_critique_shows_both_source_headers PASSED [ 31%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_and_emit_critique_prompt_conflict PASSED [ 31%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_and_emit_graph_conflict PASSED [ 31%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_and_ingest_graph_conflict PASSED [ 31%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_and_analyze_graph_conflict PASSED [ 31%]
tests/test_cli_graph_agent.py::test_emit_graph_prompt_and_ingest_critique_conflict PASSED [ 31%]
tests/test_cli_graph_agent.py::test_ingest_graph_and_emit_graph_conflict PASSED [ 31%]
tests/test_cli_graph_agent.py::test_ingest_graph_and_analyze_graph_conflict PASSED [ 31%]
tests/test_cli_graph_agent.py::test_ingest_graph_and_emit_critique_prompt_conflict PASSED [ 31%]
tests/test_cli_graph_agent.py::test_graph_agent_without_emit_or_ingest_exits_2 PASSED [ 31%]
tests/test_cli_graph_agent.py::test_baseline_valid_skill_exits_0 PASSED  [ 32%]
tests/test_cli_graph_agent.py::test_baseline_valid_skill_json_format PASSED [ 32%]
tests/test_cli_graph_agent.py::test_analyze_graph_alone_baseline PASSED  [ 32%]
tests/test_cli_graph_agent.py::test_ingest_critique_alone_baseline PASSED [ 32%]
tests/test_cli_graph_agent.py::test_ingest_graph_rejects_multiple_paths PASSED [ 32%]
tests/test_cli_history.py::test_history_passing_skill_exits_zero PASSED  [ 32%]
tests/test_cli_history.py::test_history_creates_ledger_with_one_run PASSED [ 32%]
tests/test_cli_history.py::test_history_run_twice_creates_two_entries PASSED [ 32%]
tests/test_cli_history.py::test_history_fans_out_across_multiple_paths PASSED [ 32%]
tests/test_cli_history.py::test_show_history_warns_on_extra_paths PASSED [ 32%]
tests/test_cli_history.py::test_history_records_correct_modes_symbolic_only PASSED [ 32%]
tests/test_cli_history.py::test_history_records_both_critique_and_graph_agents PASSED [ 32%]
tests/test_cli_history.py::test_history_schema_keys_present PASSED       [ 32%]
tests/test_cli_history.py::test_no_ledger_without_history_flag PASSED    [ 32%]
tests/test_cli_history.py::test_show_history_missing_ledger_exits_two PASSED [ 32%]
tests/test_cli_history.py::test_show_history_json_is_valid_json PASSED   [ 33%]
tests/test_cli_history.py::test_show_history_json_top_level_keys PASSED  [ 33%]
tests/test_cli_history.py::test_show_history_text_contains_timestamps PASSED [ 33%]
tests/test_cli_history.py::test_show_history_text_contains_pass_or_fail PASSED [ 33%]
tests/test_cli_history.py::test_history_regression_emits_warning PASSED  [ 33%]
tests/test_cli_history.py::test_history_with_emit_critique_prompt_exits_two PASSED [ 33%]
tests/test_cli_history.py::test_history_with_emit_graph_exits_two PASSED [ 33%]
tests/test_cli_history.py::test_show_history_with_history_exits_two PASSED [ 33%]
tests/test_cli_history.py::test_show_history_with_emit_critique_prompt_exits_two PASSED [ 33%]
tests/test_cli_history.py::test_show_history_with_emit_graph_exits_two PASSED [ 33%]
tests/test_cli_history.py::test_history_write_failure_warns_but_keeps_exit_code PASSED [ 33%]
tests/test_cli_history.py::test_text_output_unchanged_no_history_flag PASSED [ 33%]
tests/test_cli_history.py::test_json_output_unchanged_no_history_flag PASSED [ 33%]
tests/test_cli_history.py::test_ingest_critique_alone_unchanged PASSED   [ 33%]
tests/test_cli_history.py::test_ingest_graph_alone_unchanged PASSED      [ 33%]
tests/test_compat.py::test_claude_only_flags_model_field PASSED          [ 34%]
tests/test_compat.py::test_claude_only_flags_multiple_fields PASSED      [ 34%]
tests/test_compat.py::test_claude_only_passes_for_universal_fields PASSED [ 34%]
tests/test_compat.py::test_claude_only_severity_is_info PASSED           [ 34%]
tests/test_compat.py::test_vscode_dirname_flags_mismatch PASSED          [ 34%]
tests/test_compat.py::test_vscode_dirname_passes_when_matching PASSED    [ 34%]
tests/test_compat.py::test_vscode_dirname_skips_missing_name PASSED      [ 34%]
tests/test_compat.py::test_unverified_flags_fields_with_unknown_agents PASSED [ 34%]
tests/test_compat.py::test_unverified_passes_for_universal_only_fields PASSED [ 34%]
tests/test_compat.py::test_strict_vscode_errors_on_mismatch PASSED       [ 34%]
tests/test_compat.py::test_strict_vscode_passes_when_matching PASSED     [ 34%]
tests/test_compat.py::test_strict_vscode_all_emits_single_dirname_diagnostic PASSED [ 34%]
tests/test_compat.py::test_invalid_target_agent_raises PASSED            [ 34%]
tests/test_compat.py::test_cursor_block_scalar_flags_folded_keep PASSED  [ 34%]
tests/test_compat.py::test_cursor_block_scalar_flags_literal PASSED      [ 34%]
tests/test_compat.py::test_cursor_block_scalar_passes_folded_strip PASSED [ 34%]
tests/test_compat.py::test_cursor_block_scalar_passes_literal_strip PASSED [ 35%]
tests/test_compat.py::test_cursor_block_scalar_passes_inline_string PASSED [ 35%]
tests/test_compat.py::test_cursor_block_scalar_passes_folded_keep_explicit PASSED [ 35%]
tests/test_compat.py::test_cursor_block_scalar_target_cursor_promotes_to_warning PASSED [ 35%]
tests/test_compat.py::test_cursor_block_scalar_strict_cursor_promotes_to_error PASSED [ 35%]
tests/test_compat.py::test_cursor_block_scalar_default_severity_is_info PASSED [ 35%]
tests/test_compat.py::test_cursor_block_scalar_target_cursor_emits_single_warning PASSED [ 35%]
tests/test_compat.py::test_cursor_block_scalar_strict_cursor_replaces_info PASSED [ 35%]
tests/test_compat.py::test_cursor_block_scalar_strict_cursor_target_cursor PASSED [ 35%]
tests/test_compat.py::test_cursor_target_agent_accepts_cursor PASSED     [ 35%]
tests/test_compat_data_freshness.py::test_claude_data_is_fresh PASSED    [ 35%]
tests/test_compat_data_freshness.py::test_codex_data_is_fresh PASSED     [ 35%]
tests/test_compat_data_freshness.py::test_codex_provenance_uses_codex_date_not_claude_date PASSED [ 35%]
tests/test_compat_data_freshness.py::test_vscode_data_is_fresh PASSED    [ 35%]
tests/test_compat_data_freshness.py::test_cursor_data_is_fresh PASSED    [ 35%]
tests/test_config_loader.py::test_int_type_error_includes_offending_value PASSED [ 36%]
tests/test_config_loader.py::test_bool_type_error_includes_offending_value PASSED [ 36%]
tests/test_config_loader.py::test_str_type_error_includes_offending_value PASSED [ 36%]
tests/test_config_loader.py::test_toml_parser_respects_literal_strings_and_comments PASSED [ 36%]
tests/test_config_loader.py::test_fallback_parser_keeps_hash_inside_quotes PASSED [ 36%]
tests/test_config_loader.py::test_find_config_stops_at_git_root PASSED   [ 36%]
tests/test_config_loader.py::test_find_config_finds_config_at_git_root PASSED [ 36%]
tests/test_config_loader.py::test_cli_reports_loaded_config_path PASSED  [ 36%]
tests/test_config_validation.py::test_unknown_top_level_key_is_named PASSED [ 36%]
tests/test_config_validation.py::test_unknown_frontmatter_key_is_named PASSED [ 36%]
tests/test_config_validation.py::test_extension_fields_must_be_a_list_of_strings PASSED [ 36%]
tests/test_config_validation.py::test_extension_fields_rejects_a_list_of_non_strings PASSED [ 36%]
tests/test_config_validation.py::test_reserved_words_must_be_a_list_of_strings PASSED [ 36%]
tests/test_config_validation.py::test_frontmatter_section_must_be_a_table PASSED [ 36%]
tests/test_config_validation.py::test_ignore_must_be_a_list_of_strings PASSED [ 36%]
tests/test_config_validation.py::test_malformed_toml_is_rejected_with_the_offending_line PASSED [ 37%]
tests/test_config_validation.py::test_reserved_words_round_trip PASSED   [ 37%]
tests/test_config_validation.py::test_ignore_round_trip PASSED           [ 37%]
tests/test_config_validation.py::test_no_config_path_yields_defaults PASSED [ 37%]
tests/test_config_validation.py::test_fallback_parser_rejects_a_line_without_an_equals SKIPPED [ 37%]
tests/test_config_validation.py::test_fallback_parser_rejects_an_unterminated_section_header SKIPPED [ 37%]
tests/test_config_validation.py::test_fallback_parser_reads_booleans SKIPPED [ 37%]
tests/test_config_validation.py::test_fallback_parser_reads_integers SKIPPED [ 37%]
tests/test_config_validation.py::test_discovery_returns_none_when_nothing_is_found PASSED [ 37%]
tests/test_config_validation.py::test_discovery_accepts_a_file_anchor PASSED [ 37%]
tests/test_config_validation.py::test_discovery_prefers_the_nearest_config PASSED [ 37%]
tests/test_critique_parser.py::test_parse_minimal_valid_response PASSED  [ 37%]
tests/test_critique_parser.py::test_parse_response_with_findings PASSED  [ 37%]
tests/test_critique_parser.py::test_parse_response_with_missing_context PASSED [ 37%]
tests/test_critique_parser.py::test_missing_context_over_cap_rejected PASSED [ 37%]
tests/test_critique_parser.py::test_findings_over_cap_rejected PASSED    [ 37%]
tests/test_critique_parser.py::test_list_exactly_at_cap_is_accepted PASSED [ 38%]
tests/test_critique_parser.py::test_parse_response_with_contradictions PASSED [ 38%]
tests/test_critique_parser.py::test_parse_all_severity_values PASSED     [ 38%]
tests/test_critique_parser.py::test_parse_boundary_scores PASSED         [ 38%]
tests/test_critique_parser.py::test_parse_strips_json_code_fence PASSED  [ 38%]
tests/test_critique_parser.py::test_parse_strips_plain_code_fence PASSED [ 38%]
tests/test_critique_parser.py::test_parse_strips_leading_trailing_whitespace PASSED [ 38%]
tests/test_critique_parser.py::test_parse_strips_prose_preamble PASSED   [ 38%]
tests/test_critique_parser.py::test_parse_strips_inline_prose_preamble PASSED [ 38%]
tests/test_critique_parser.py::test_json_error_raised_for_invalid_json PASSED [ 38%]
tests/test_critique_parser.py::test_json_error_is_subclass_of_parse_error PASSED [ 38%]
tests/test_critique_parser.py::test_json_error_message_includes_preview PASSED [ 38%]
tests/test_critique_parser.py::test_json_error_message_includes_position PASSED [ 38%]
tests/test_critique_parser.py::test_json_error_preserves_cause PASSED    [ 38%]
tests/test_critique_parser.py::test_schema_error_for_missing_required_field PASSED [ 38%]
tests/test_critique_parser.py::test_schema_error_for_extra_top_level_field PASSED [ 39%]
tests/test_critique_parser.py::test_schema_error_for_wrong_score_type PASSED [ 39%]
tests/test_critique_parser.py::test_schema_error_for_bool_score PASSED   [ 39%]
tests/test_critique_parser.py::test_schema_error_for_missing_finding_field PASSED [ 39%]
tests/test_critique_parser.py::test_schema_error_for_extra_finding_field PASSED [ 39%]
tests/test_critique_parser.py::test_schema_error_for_finding_not_dict PASSED [ 39%]
tests/test_critique_parser.py::test_schema_error_for_contradiction_missing_field PASSED [ 39%]
tests/test_critique_parser.py::test_schema_error_for_missing_context_item_not_string PASSED [ 39%]
tests/test_critique_parser.py::test_schema_error_for_top_level_not_object PASSED [ 39%]
tests/test_critique_parser.py::test_value_error_for_score_below_zero PASSED [ 39%]
tests/test_critique_parser.py::test_value_error_for_score_above_hundred PASSED [ 39%]
tests/test_critique_parser.py::test_value_error_for_invalid_severity_string PASSED [ 39%]
tests/test_critique_parser.py::test_value_error_is_subclass_of_parse_error PASSED [ 39%]
tests/test_critique_prompt.py::test_render_contains_skill_body PASSED    [ 39%]
tests/test_critique_prompt.py::test_render_contains_skill_frontmatter PASSED [ 39%]
tests/test_critique_prompt.py::test_render_contains_schema_version PASSED [ 40%]
tests/test_critique_prompt.py::test_render_contains_score_field_names PASSED [ 40%]
tests/test_critique_prompt.py::test_render_contains_required_field_names PASSED [ 40%]
tests/test_critique_prompt.py::test_render_contains_worked_example PASSED [ 40%]
tests/test_critique_prompt.py::test_render_contains_severity_options PASSED [ 40%]
tests/test_critique_prompt.py::test_render_instructs_json_only_response PASSED [ 40%]
tests/test_critique_prompt.py::test_render_multi_section_contains_section_headings PASSED [ 40%]
tests/test_critique_prompt.py::test_render_skill_with_code_blocks_contains_code PASSED [ 40%]
tests/test_critique_prompt.py::test_render_is_deterministic PASSED       [ 40%]
tests/test_critique_prompt.py::test_render_same_input_same_output_across_instances PASSED [ 40%]
tests/test_critique_prompt.py::test_render_different_skills_produce_different_prompts PASSED [ 40%]
tests/test_critique_prompt.py::test_claude_prompt_agent_id PASSED        [ 40%]
tests/test_critique_prompt.py::test_codex_prompt_agent_id PASSED         [ 40%]
tests/test_critique_prompt.py::test_cursor_prompt_agent_id PASSED        [ 40%]
tests/test_critique_schema.py::test_critique_finding_construction PASSED [ 40%]
tests/test_critique_schema.py::test_critique_finding_invalid_severity PASSED [ 40%]
tests/test_critique_schema.py::test_critique_finding_is_frozen PASSED    [ 41%]
tests/test_critique_schema.py::test_critique_finding_equality PASSED     [ 41%]
tests/test_critique_schema.py::test_critique_finding_hashable PASSED     [ 41%]
tests/test_critique_schema.py::test_critique_finding_asdict_roundtrip PASSED [ 41%]
tests/test_critique_schema.py::test_contradiction_construction PASSED    [ 41%]
tests/test_critique_schema.py::test_contradiction_is_frozen PASSED       [ 41%]
tests/test_critique_schema.py::test_contradiction_hashable PASSED        [ 41%]
tests/test_critique_schema.py::test_contradiction_asdict_roundtrip PASSED [ 41%]
tests/test_critique_schema.py::test_semantic_critique_valid_construction PASSED [ 41%]
tests/test_critique_schema.py::test_semantic_critique_score_zero_boundary PASSED [ 41%]
tests/test_critique_schema.py::test_semantic_critique_score_hundred_boundary PASSED [ 41%]
tests/test_critique_schema.py::test_semantic_critique_clarity_below_zero_raises PASSED [ 41%]
tests/test_critique_schema.py::test_semantic_critique_clarity_above_hundred_raises PASSED [ 41%]
tests/test_critique_schema.py::test_semantic_critique_completeness_out_of_range_raises PASSED [ 41%]
tests/test_critique_schema.py::test_semantic_critique_executability_out_of_range_raises PASSED [ 41%]
tests/test_critique_schema.py::test_semantic_critique_score_type_error_includes_bad_value PASSED [ 42%]
tests/test_critique_schema.py::test_semantic_critique_bool_rejected_as_score PASSED [ 42%]
tests/test_critique_schema.py::test_semantic_critique_is_frozen PASSED   [ 42%]
tests/test_critique_schema.py::test_semantic_critique_with_findings PASSED [ 42%]
tests/test_critique_schema.py::test_semantic_critique_with_contradictions PASSED [ 42%]
tests/test_critique_schema.py::test_semantic_critique_asdict_roundtrip PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_opening_escape_parity[0] PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_opening_escape_parity[1] PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_opening_escape_parity[2] PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_opening_escape_parity[3] PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_opening_escape_parity[4] PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_opening_escape_parity[5] PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_runs_and_literal_backslashes[\\`` [example](missing.md) ` [helper](helper.py)-targets0] PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_runs_and_literal_backslashes[\\`` [helper](helper.py) ``-targets1] PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_runs_and_literal_backslashes[`code\\` [helper](helper.py) `-targets2] PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_runs_and_literal_backslashes[``code\\`` [helper](helper.py) ``-targets3] PASSED [ 42%]
tests/test_dependency_numeric_regressions.py::test_backtick_runs_and_literal_backslashes[`` code\\` [example](missing.md) `` [helper](helper.py)-targets4] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_backtick_runs_and_literal_backslashes[\\` [helper](helper.py) ``-targets5] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_backtick_runs_and_literal_backslashes[` [helper](helper.py) ``-targets6] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_backtick_runs_and_literal_backslashes[- `unclosed\n- [helper](helper.py) `-targets7] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_backtick_runs_and_literal_backslashes[\\`\n[helper](helper.py)\n`-targets8] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_and_paragraph_continuations_keep_dependencies[- Steps:\n    - [helper](helper.py)] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_and_paragraph_continuations_keep_dependencies[- Steps:\n\t- [helper](helper.py)] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_and_paragraph_continuations_keep_dependencies[1. Steps:\n    1. [helper](helper.py)] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_and_paragraph_continuations_keep_dependencies[- Steps:\n    [helper](helper.py)] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_and_paragraph_continuations_keep_dependencies[- Steps:\n\n    [helper](helper.py)] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_and_paragraph_continuations_keep_dependencies[-\tSteps:\n\n    [helper](helper.py)] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_and_paragraph_continuations_keep_dependencies[1.\tSteps:\n\n    [helper](helper.py)] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_and_paragraph_continuations_keep_dependencies[- Steps:\n    - Nested:\n        [helper](helper.py)] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_and_paragraph_continuations_keep_dependencies[Paragraph\n    [helper](helper.py)] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_and_paragraph_continuations_keep_dependencies[- Steps:\n    [ref]: helper.py\n\n    [ref]] PASSED [ 43%]
tests/test_dependency_numeric_regressions.py::test_list_code_examples_stay_excluded[- Steps:\n\n      [example](missing.md)] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_list_code_examples_stay_excluded[- Steps:\n    ```md\n    [example](missing.md)\n    ```] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_list_code_examples_stay_excluded[- Steps:\n    - Nested:\n\n          [example](missing.md)] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_list_code_examples_stay_excluded[    - [example](missing.md)] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_list_code_examples_stay_excluded[- Steps:\n\n\t  [example](missing.md)] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[[helper](helper.py)-True-True] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[\\` [helper](helper.py) `-True-True] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[- Steps:\n    - [helper](helper.py)-True-True] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[- Steps:\n\n    [helper](helper.py)-True-True] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[Paragraph\n    [helper](helper.py)-True-True] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[> - Steps:\n>     [helper](helper.py)-False-True] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[- Steps:\nlazy continuation\n\n    [helper](helper.py)-False-False] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[- - Steps:\n\n    [helper](helper.py)-False-True] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[-\n\n     [helper](helper.py)-True-True] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[`[example](helper.py)`-True-False] PASSED [ 44%]
tests/test_dependency_numeric_regressions.py::test_dependency_closure_controls_real_trusted_comparison[- Steps:\n\n      [example](helper.py)-True-False] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{}-1e999] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{}--1e999] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{}-NaN] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{}-Infinity] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{}--Infinity] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{{"value":{}}}-1e999] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{{"value":{}}}--1e999] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{{"value":{}}}-NaN] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{{"value":{}}}-Infinity] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{{"value":{}}}--Infinity] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[[{}]-1e999] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[[{}]--1e999] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[[{}]-NaN] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[[{}]-Infinity] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[[{}]--Infinity] PASSED [ 45%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{{"nested":[{{"value":{}}}]}}-1e999] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{{"nested":[{{"value":{}}}]}}--1e999] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{{"nested":[{{"value":{}}}]}}-NaN] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{{"nested":[{{"value":{}}}]}}-Infinity] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_shared_decoder_rejects_all_nonfinite_numbers[{{"nested":[{{"value":{}}}]}}--Infinity] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_finite_exponents_preserve_canonical_bytes_and_digests[1e308] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_finite_exponents_preserve_canonical_bytes_and_digests[-1e308] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_finite_exponents_preserve_canonical_bytes_and_digests[1.7976931348623157e308] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_finite_exponents_preserve_canonical_bytes_and_digests[1e-308] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_finite_exponents_preserve_canonical_bytes_and_digests[5e-324] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_finite_exponents_preserve_canonical_bytes_and_digests[1e-999] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_finite_exponents_preserve_canonical_bytes_and_digests[-1e-999] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_finite_exponents_preserve_canonical_bytes_and_digests[0e999] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_authentic_promptfoo_overflow_is_atomic_cli_error[config-1e999] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_authentic_promptfoo_overflow_is_atomic_cli_error[config--1e999] PASSED [ 46%]
tests/test_dependency_numeric_regressions.py::test_authentic_promptfoo_overflow_is_atomic_cli_error[bound-row-1e999] PASSED [ 47%]
tests/test_dependency_numeric_regressions.py::test_authentic_promptfoo_overflow_is_atomic_cli_error[bound-row--1e999] PASSED [ 47%]
tests/test_dependency_numeric_regressions.py::test_authentic_promptfoo_overflow_is_atomic_cli_error[unbound-row-1e999] PASSED [ 47%]
tests/test_dependency_numeric_regressions.py::test_authentic_promptfoo_overflow_is_atomic_cli_error[unbound-row--1e999] PASSED [ 47%]
tests/test_description.py::test_high_quality_description_scores_above_60 PASSED [ 47%]
tests/test_description.py::test_low_quality_description_scores_below_40 PASSED [ 47%]
tests/test_description.py::test_empty_description_scores_zero PASSED     [ 47%]
tests/test_description.py::test_vague_description_penalized PASSED       [ 47%]
tests/test_description.py::test_seamless_and_empowering_are_vague PASSED [ 47%]
tests/test_description.py::test_action_verb_at_start_boosts_score PASSED [ 47%]
tests/test_description.py::test_trigger_phrase_boosts_score PASSED       [ 47%]
tests/test_description.py::test_very_short_description_penalized PASSED  [ 47%]
tests/test_description.py::test_very_long_description_penalized PASSED   [ 47%]
tests/test_description.py::test_quality_rule_returns_info_diagnostic PASSED [ 47%]
tests/test_description.py::test_quality_rule_skips_missing_description PASSED [ 47%]
tests/test_description.py::test_quality_rule_skips_empty_description PASSED [ 48%]
tests/test_description.py::test_min_score_rule_warns_below_threshold PASSED [ 48%]
tests/test_description.py::test_min_score_rule_passes_above_threshold PASSED [ 48%]
tests/test_description.py::test_min_score_rule_skips_missing_description PASSED [ 48%]
tests/test_description.py::test_comprehensive_alone_does_not_penalize PASSED [ 48%]
tests/test_description.py::test_third_person_verb_forms_count_via_stem_normalization PASSED [ 48%]
tests/test_description.py::test_newly_added_verbs_all_count_as_action_verbs PASSED [ 48%]
tests/test_description.py::test_issue_2_regression_investigate_description PASSED [ 48%]
tests/test_description.py::test_ing_form_counts_as_action_verb PASSED    [ 48%]
tests/test_description.py::test_ed_form_counts_as_action_verb PASSED     [ 48%]
tests/test_description.py::test_negative_handles_still_excluded PASSED   [ 48%]
tests/test_description.py::test_negative_triggers_still_excluded PASSED  [ 48%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[add] PASSED [ 48%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[brainstorm] PASSED [ 48%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[bundle] PASSED [ 48%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[choose] PASSED [ 48%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[debug] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[design] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[dispatch] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[finish] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[guide] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[implement] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[package] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[plan] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[receive] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[review] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[solve] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[start] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[use] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[verify] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_added_verb_registers_in_every_inflection[write] PASSED [ 49%]
tests/test_description_scorer_tuning.py::test_use_opener_no_longer_scores_zero_on_action PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_review_and_implement_count_as_actions PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_vague_directives_are_still_not_action_verbs PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_handle_and_trigger_remain_excluded PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_strong_trigger_form_is_recognized[This skill should be used when the user asks to "create a slash command".] PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_strong_trigger_form_is_recognized[Used when a release candidate is promoted to staging.] PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_strong_trigger_form_is_recognized[Generates release notes when the user requests a changelog for a tag.] PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_strong_trigger_form_is_recognized[Extracts traces when asked to diagnose a failing CI job.] PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_canonical_opener_now_reaches_full_trigger_credit PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_prose_about_users_is_not_a_trigger PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_contextual_trigger_earns_partial_credit[Guidance for distinctive visual design when building new UI.] PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_contextual_trigger_earns_partial_credit[Validates SKILL.md files when linting a skill directory.] PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_contextual_trigger_earns_partial_credit[Checks the plan before implementing any change to the schema.] PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_contextual_trigger_earns_partial_credit[Summarizes the diff after merging a pull request into main.] PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_incidental_gerund_does_not_earn_explicit_trigger_credit[A nice helper when using things.] PASSED [ 50%]
tests/test_description_scorer_tuning.py::test_incidental_gerund_does_not_earn_explicit_trigger_credit[Generic utility, use before running anything.] PASSED [ 51%]
tests/test_description_scorer_tuning.py::test_incidental_gerund_does_not_earn_explicit_trigger_credit[Basic tool that is good after installing it.] PASSED [ 51%]
tests/test_description_scorer_tuning.py::test_two_contextual_forms_do_not_beat_one_explicit_form PASSED [ 51%]
tests/test_description_scorer_tuning.py::test_scorer_still_separates_good_descriptions_from_filler PASSED [ 51%]
tests/test_description_scorer_tuning.py::test_every_dimension_is_explained PASSED [ 51%]
tests/test_description_scorer_tuning.py::test_explanation_names_the_matched_action_verb PASSED [ 51%]
tests/test_description_scorer_tuning.py::test_explanation_names_the_matched_trigger_text PASSED [ 51%]
tests/test_description_scorer_tuning.py::test_explanation_distinguishes_contextual_from_explicit PASSED [ 51%]
tests/test_description_scorer_tuning.py::test_explanation_reports_a_failure_when_nothing_matched PASSED [ 51%]
tests/test_description_scorer_tuning.py::test_explanation_lists_the_vague_words_it_penalized PASSED [ 51%]
tests/test_disclosure.py::test_metadata_budget_warns_for_large_frontmatter PASSED [ 51%]
tests/test_disclosure.py::test_metadata_budget_passes_for_small_frontmatter PASSED [ 51%]
tests/test_disclosure.py::test_metadata_budget_handles_no_frontmatter PASSED [ 51%]
tests/test_disclosure.py::test_body_budget_warns_for_large_body PASSED   [ 51%]
tests/test_disclosure.py::test_body_budget_passes_for_small_body PASSED  [ 51%]
tests/test_disclosure.py::test_body_budget_handles_empty_body PASSED     [ 51%]
tests/test_disclosure.py::test_body_bloat_flags_large_code_block PASSED  [ 52%]
tests/test_disclosure.py::test_body_bloat_flags_large_table PASSED       [ 52%]
tests/test_disclosure.py::test_body_bloat_does_not_sum_separate_small_tables PASSED [ 52%]
tests/test_disclosure.py::test_body_bloat_flags_base64 PASSED            [ 52%]
tests/test_disclosure.py::test_body_bloat_passes_for_clean_body PASSED   [ 52%]
tests/test_disclosure.py::test_body_bloat_handles_empty_body PASSED      [ 52%]
tests/test_disclosure.py::test_base64_rejects_repeated_single_char PASSED [ 52%]
tests/test_disclosure.py::test_base64_rejects_hex_hash PASSED            [ 52%]
tests/test_disclosure.py::test_base64_rejects_all_uppercase PASSED       [ 52%]
tests/test_explain_score.py::test_full_credit_description PASSED         [ 52%]
tests/test_explain_score.py::test_zero_credit_description PASSED         [ 52%]
tests/test_explain_score.py::test_mid_range_description PASSED           [ 52%]
tests/test_explain_score.py::test_json_breakdown_present PASSED          [ 52%]
tests/test_explain_score.py::test_text_flag_off_suppresses_breakdown PASSED [ 52%]
tests/test_explain_score.py::test_text_explain_score_shows_breakdown PASSED [ 52%]
tests/test_explain_score.py::test_scorer_dimensions_match_the_published_weights PASSED [ 53%]
tests/test_explain_score.py::test_no_dimension_can_exceed_its_weight PASSED [ 53%]
tests/test_explain_score.py::test_weights_sum_to_one_hundred PASSED      [ 53%]
tests/test_explain_score.py::test_explain_score_line_renders_every_weighted_dimension PASSED [ 53%]
tests/test_fail_on_regression.py::test_regression_detected PASSED        [ 53%]
tests/test_fail_on_regression.py::test_no_regression_when_passing PASSED [ 53%]
tests/test_fail_on_regression.py::TestFailOnRegressionCLI::test_flag_set_fires_exit_1 PASSED [ 53%]
tests/test_fail_on_regression.py::TestFailOnRegressionCLI::test_flag_set_no_regression_exits_0 PASSED [ 53%]
tests/test_fail_on_regression.py::TestFailOnRegressionCLI::test_flag_unset_regression_warns_exit_0 PASSED [ 53%]
tests/test_format_github.py::TestEscapeData::test_percent_escaped_first PASSED [ 53%]
tests/test_format_github.py::TestEscapeData::test_carriage_return_escaped PASSED [ 53%]
tests/test_format_github.py::TestEscapeData::test_newline_escaped PASSED [ 53%]
tests/test_format_github.py::TestEscapeData::test_colon_left_literal PASSED [ 53%]
tests/test_format_github.py::TestEscapeData::test_comma_left_literal PASSED [ 53%]
tests/test_format_github.py::TestEscapeData::test_order_percent_before_others PASSED [ 53%]
tests/test_format_github.py::TestEscapeProperty::test_colon_escaped PASSED [ 54%]
tests/test_format_github.py::TestEscapeProperty::test_comma_escaped PASSED [ 54%]
tests/test_format_github.py::TestEscapeProperty::test_all_five_chars PASSED [ 54%]
tests/test_format_github.py::TestFormatGithub::test_error_diagnostic_produces_error_command PASSED [ 54%]
tests/test_format_github.py::TestFormatGithub::test_warning_diagnostic_produces_warning_command PASSED [ 54%]
tests/test_format_github.py::TestFormatGithub::test_info_diagnostic_produces_notice_command PASSED [ 54%]
tests/test_format_github.py::TestFormatGithub::test_no_line_omits_line_property PASSED [ 54%]
tests/test_format_github.py::TestFormatGithub::test_message_with_special_chars_escaped PASSED [ 54%]
tests/test_format_github.py::TestFormatGithub::test_multiple_diagnostics_across_files PASSED [ 54%]
tests/test_format_github.py::test_format_github_cli_produces_gha_commands PASSED [ 54%]
tests/test_format_github.py::test_format_github_cli_with_warning PASSED  [ 54%]
tests/test_format_github.py::test_format_github_cli_with_info PASSED     [ 54%]
tests/test_formatter_golden.py::test_renderer_matches_golden[text] PASSED [ 54%]
tests/test_formatter_golden.py::test_renderer_matches_golden[text_plain] PASSED [ 54%]
tests/test_formatter_golden.py::test_renderer_matches_golden[json] PASSED [ 54%]
tests/test_formatter_golden.py::test_renderer_matches_golden[markdown] PASSED [ 54%]
tests/test_formatter_golden.py::test_renderer_matches_golden[github] PASSED [ 55%]
tests/test_formatter_golden.py::test_renderer_matches_golden[agent] PASSED [ 55%]
tests/test_formatter_golden.py::test_every_renderer_has_a_golden_file PASSED [ 55%]
tests/test_formatter_golden.py::test_color_codes_are_absent_from_the_text_golden PASSED [ 55%]
tests/test_formatter_golden.py::test_text_renderer_emits_ansi_when_color_is_on PASSED [ 55%]
tests/test_formatter_golden.py::test_path_normalizer_restores_windows_separators PASSED [ 55%]
tests/test_formatter_golden.py::test_path_normalizer_leaves_the_markdown_pipe_escape_alone PASSED [ 55%]
tests/test_formatter_golden.py::test_breakdown_key_matches_what_the_renderers_look_up PASSED [ 55%]
tests/test_frontmatter.py::test_name_required_fires_when_missing PASSED  [ 55%]
tests/test_frontmatter.py::test_name_required_passes_for_valid_file PASSED [ 55%]
tests/test_frontmatter.py::test_name_rejects_long_name PASSED            [ 55%]
tests/test_frontmatter.py::test_name_accepts_name_at_length_boundary PASSED [ 55%]
tests/test_frontmatter.py::test_name_rejects_name_one_over_boundary PASSED [ 55%]
tests/test_frontmatter.py::test_name_rejects_uppercase PASSED            [ 55%]
tests/test_frontmatter.py::test_name_accepts_lowercase_with_hyphens PASSED [ 55%]
tests/test_frontmatter.py::test_name_accepts_lowercase_with_numbers PASSED [ 56%]
tests/test_frontmatter.py::test_name_rejects_spaces PASSED               [ 56%]
tests/test_frontmatter.py::test_name_rejects_reserved_word_claude PASSED [ 56%]
tests/test_frontmatter.py::test_name_rejects_reserved_word_anthropic PASSED [ 56%]
tests/test_frontmatter.py::test_name_accepts_unreserved_name PASSED      [ 56%]
tests/test_frontmatter.py::test_reserved_words_configurable_via_config PASSED [ 56%]
tests/test_frontmatter.py::test_reserved_words_empty_config_reverts_to_defaults PASSED [ 56%]
tests/test_frontmatter.py::test_description_required_fires_when_missing PASSED [ 56%]
tests/test_frontmatter.py::test_description_required_passes_for_valid_file PASSED [ 56%]
tests/test_frontmatter.py::test_description_rejects_empty PASSED         [ 56%]
tests/test_frontmatter.py::test_description_accepts_non_empty PASSED     [ 56%]
tests/test_frontmatter.py::test_description_rejects_over_1024_chars PASSED [ 56%]
tests/test_frontmatter.py::test_description_accepts_exactly_1024_chars PASSED [ 56%]
tests/test_frontmatter.py::test_description_rejects_xml_tags PASSED      [ 56%]
tests/test_frontmatter.py::test_description_accepts_no_xml_tags PASSED   [ 56%]
tests/test_frontmatter.py::test_description_rejects_first_person PASSED  [ 57%]
tests/test_frontmatter.py::test_description_rejects_second_person PASSED [ 57%]
tests/test_frontmatter.py::test_description_accepts_third_person PASSED  [ 57%]
tests/test_frontmatter.py::test_description_accepts_third_person_with_verbs PASSED [ 57%]
tests/test_frontmatter.py::test_unknown_field_triggers_warning PASSED    [ 57%]
tests/test_frontmatter.py::test_known_fields_produce_no_warning PASSED   [ 57%]
tests/test_frontmatter.py::test_field_line_does_not_match_body_content PASSED [ 57%]
tests/test_frontmatter.py::test_field_line_reports_correct_frontmatter_line PASSED [ 57%]
tests/test_frontmatter.py::test_description_rejects_first_person_possessive PASSED [ 57%]
tests/test_frontmatter.py::test_name_required_hints_at_markdown_heading PASSED [ 57%]
tests/test_frontmatter.py::test_description_required_hints_at_markdown_heading PASSED [ 57%]
tests/test_frontmatter.py::test_name_required_hint_absent_when_heading_only_for_other_field PASSED [ 57%]
tests/test_frontmatter.py::test_name_required_no_hint_for_plain_missing PASSED [ 57%]
tests/test_frontmatter.py::test_description_required_no_hint_for_plain_missing PASSED [ 57%]
tests/test_frontmatter.py::test_heading_hint_does_not_match_body_headings PASSED [ 57%]
tests/test_golden_warnings.py::test_golden_case[claude-doc-helper] PASSED [ 57%]
tests/test_golden_warnings.py::test_golden_case[clean-baseline] PASSED   [ 58%]
tests/test_golden_warnings.py::test_golden_case[person-voice-first] PASSED [ 58%]
tests/test_golden_warnings.py::test_golden_case[person-voice-second] PASSED [ 58%]
tests/test_golden_warnings.py::test_golden_case[unknown-fields] PASSED   [ 58%]
tests/test_golden_warnings.py::test_every_case_directory_has_an_expected_file PASSED [ 58%]
tests/test_golden_warnings.py::test_case_still_triggers_its_rule[unknown-fields-frontmatter.field.unknown0] PASSED [ 58%]
tests/test_golden_warnings.py::test_case_still_triggers_its_rule[unknown-fields-frontmatter.field.unknown1] PASSED [ 58%]
tests/test_golden_warnings.py::test_case_still_triggers_its_rule[claude-doc-helper-frontmatter.name.reserved-word] PASSED [ 58%]
tests/test_golden_warnings.py::test_case_still_triggers_its_rule[person-voice-first-frontmatter.description.person-voice] PASSED [ 58%]
tests/test_golden_warnings.py::test_case_still_triggers_its_rule[person-voice-second-frontmatter.description.person-voice] PASSED [ 58%]
tests/test_golden_warnings.py::test_clean_baseline_produces_no_warnings_or_errors PASSED [ 58%]
tests/test_golden_warnings.py::test_person_voice_reports_the_offending_phrase PASSED [ 58%]
tests/test_graph_analyzers.py::test_orphaned_capabilities_fires_for_isolated_capability PASSED [ 58%]
tests/test_graph_analyzers.py::test_orphaned_capabilities_silent_when_connected PASSED [ 58%]
tests/test_graph_analyzers.py::test_orphaned_capabilities_includes_line_number PASSED [ 58%]
tests/test_graph_analyzers.py::test_unused_inputs_fires_for_unreferenced_body_input PASSED [ 59%]
tests/test_graph_analyzers.py::test_unused_inputs_silent_when_no_inputs_declared PASSED [ 59%]
tests/test_graph_analyzers.py::test_unused_inputs_does_not_fire_for_frontmatter_tools PASSED [ 59%]
tests/test_graph_analyzers.py::test_unproduced_outputs_fires_for_output_with_no_produces_edge PASSED [ 59%]
tests/test_graph_analyzers.py::test_unproduced_outputs_silent_when_no_outputs_declared PASSED [ 59%]
tests/test_graph_analyzers.py::test_empty_descriptions_fires_for_headingonly_capability PASSED [ 59%]
tests/test_graph_analyzers.py::test_empty_descriptions_identifies_correct_capability PASSED [ 59%]
tests/test_graph_analyzers.py::test_empty_descriptions_silent_when_all_described PASSED [ 59%]
tests/test_graph_analyzers.py::test_unreferenced_tools_fires_for_frontmatter_tool_not_in_body PASSED [ 59%]
tests/test_graph_analyzers.py::test_unreferenced_tools_silent_when_no_frontmatter_tools PASSED [ 59%]
tests/test_graph_analyzers.py::test_unreferenced_tools_does_not_fire_for_body_inputs PASSED [ 59%]
tests/test_graph_analyzers.py::test_run_graph_analyzers_returns_flat_list PASSED [ 59%]
tests/test_graph_analyzers.py::test_run_graph_analyzers_includes_orphaned_rule_for_fixture PASSED [ 59%]
tests/test_graph_analyzers.py::test_run_graph_analyzers_is_deterministic PASSED [ 59%]
tests/test_graph_analyzers.py::test_run_graph_analyzers_returns_empty_for_empty_graph PASSED [ 59%]
tests/test_graph_analyzers.py::test_graph_analyzers_tuple_has_five_entries PASSED [ 60%]
tests/test_graph_analyzers.py::test_all_analyzer_diagnostics_are_warnings PASSED [ 60%]
tests/test_graph_divergence.py::test_clean_response_no_divergence PASSED [ 60%]
tests/test_graph_divergence.py::test_extra_capabilities_no_divergence PASSED [ 60%]
tests/test_graph_divergence.py::test_empty_agent_graph_no_divergence PASSED [ 60%]
tests/test_graph_divergence.py::test_run_divergence_analyzers_no_divergence_returns_empty PASSED [ 60%]
tests/test_graph_divergence.py::test_contradiction_fires_one_error PASSED [ 60%]
tests/test_graph_divergence.py::test_contradiction_diagnostic_is_error_severity PASSED [ 60%]
tests/test_graph_divergence.py::test_contradiction_rule_id PASSED        [ 60%]
tests/test_graph_divergence.py::test_contradiction_message_names_capability_and_output PASSED [ 60%]
tests/test_graph_divergence.py::test_requires_contradiction_fires_error PASSED [ 60%]
tests/test_graph_divergence.py::test_all_divergence_diagnostics_are_error PASSED [ 60%]
tests/test_graph_divergence.py::test_divergence_analyzers_tuple_non_empty PASSED [ 60%]
tests/test_graph_divergence.py::test_agent_finds_cap_not_in_heuristic_no_divergence PASSED [ 60%]
tests/test_graph_heuristic.py::test_imperative_verbs_tuple_sorted PASSED [ 60%]
tests/test_graph_heuristic.py::test_input_section_aliases_tuple_sorted PASSED [ 60%]
tests/test_graph_heuristic.py::test_output_section_aliases_tuple_sorted PASSED [ 61%]
tests/test_graph_heuristic.py::test_basic_io_capability_count PASSED     [ 61%]
tests/test_graph_heuristic.py::test_basic_io_capability_name PASSED      [ 61%]
tests/test_graph_heuristic.py::test_basic_io_capability_description PASSED [ 61%]
tests/test_graph_heuristic.py::test_basic_io_input_count PASSED          [ 61%]
tests/test_graph_heuristic.py::test_basic_io_input_kinds PASSED          [ 61%]
tests/test_graph_heuristic.py::test_basic_io_output_count PASSED         [ 61%]
tests/test_graph_heuristic.py::test_basic_io_output_kinds PASSED         [ 61%]
tests/test_graph_heuristic.py::test_basic_io_edge_count PASSED           [ 61%]
tests/test_graph_heuristic.py::test_basic_io_edges_correct_kinds PASSED  [ 61%]
tests/test_graph_heuristic.py::test_basic_io_source_is_heuristic PASSED  [ 61%]
tests/test_graph_heuristic.py::test_frontmatter_tools_input_count PASSED [ 61%]
tests/test_graph_heuristic.py::test_frontmatter_tools_all_kind_tool PASSED [ 61%]
tests/test_graph_heuristic.py::test_frontmatter_tools_names PASSED       [ 61%]
tests/test_graph_heuristic.py::test_frontmatter_tools_line_is_none PASSED [ 61%]
tests/test_graph_heuristic.py::test_frontmatter_tools_no_capabilities PASSED [ 62%]
tests/test_graph_heuristic.py::test_imperative_caps_count PASSED         [ 62%]
tests/test_graph_heuristic.py::test_imperative_caps_names_are_imperative PASSED [ 62%]
tests/test_graph_heuristic.py::test_imperative_caps_overview_excluded PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[Phase 1: Implement Tools] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[Phase 2 - Build the index] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[Step 3: Validate output] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[Section 4: Generate report] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[Part 1: Create artifact] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[Chapter 2: Extract data] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[1. Implement Tools] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[2) Build the index] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[3.  Validate output] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[1.1 Understand the API] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[2.1 Set Up Project Structure] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[4.2 Create 10 Evaluation Questions] PASSED [ 62%]
tests/test_graph_heuristic.py::test_section_prefix_stripped_for_imperative_check[1.1.1 Implement helper] PASSED [ 63%]
tests/test_graph_heuristic.py::test_strip_section_prefix[Phase 1: Implement Tools-Implement Tools] PASSED [ 63%]
tests/test_graph_heuristic.py::test_strip_section_prefix[Step 2. Build-Build] PASSED [ 63%]
tests/test_graph_heuristic.py::test_strip_section_prefix[Section 3: Generate-Generate] PASSED [ 63%]
tests/test_graph_heuristic.py::test_strip_section_prefix[1. Implement-Implement] PASSED [ 63%]
tests/test_graph_heuristic.py::test_strip_section_prefix[Plain heading no prefix-Plain heading no prefix] PASSED [ 63%]
tests/test_graph_heuristic.py::test_strip_section_prefix_only_strips_one_prefix PASSED [ 63%]
tests/test_graph_heuristic.py::test_imperative_verbs_includes_real_world_verbs PASSED [ 63%]
tests/test_graph_heuristic.py::test_heuristic_capability_names_strip_section_prefix PASSED [ 63%]
tests/test_graph_heuristic.py::test_no_structure_empty_graph PASSED      [ 63%]
tests/test_graph_heuristic.py::test_aliases_prerequisites_section_recognized PASSED [ 63%]
tests/test_graph_heuristic.py::test_aliases_produces_section_recognized PASSED [ 63%]
tests/test_graph_heuristic.py::test_aliases_capability_and_edges PASSED  [ 63%]
tests/test_graph_heuristic.py::test_duplicate_section_outputs_merged PASSED [ 63%]
tests/test_graph_heuristic.py::test_duplicate_section_total_outputs PASSED [ 63%]
tests/test_graph_heuristic.py::test_duplicate_section_edges PASSED       [ 64%]
tests/test_graph_heuristic.py::test_equal_on_repeated_extraction PASSED  [ 64%]
tests/test_graph_heuristic.py::test_hash_equal_on_repeated_extraction PASSED [ 64%]
tests/test_graph_heuristic.py::test_tuple_ordering_is_stable PASSED      [ 64%]
tests/test_graph_heuristic.py::test_stable_ids_for_basic_io PASSED       [ 64%]
tests/test_graph_heuristic.py::test_make_id_is_deterministic PASSED      [ 64%]
tests/test_graph_heuristic.py::test_make_id_differs_with_different_line PASSED [ 64%]
tests/test_graph_heuristic.py::test_make_id_differs_with_none_vs_int PASSED [ 64%]
tests/test_graph_heuristic.py::test_make_id_is_eight_hex_chars PASSED    [ 64%]
tests/test_graph_heuristic.py::test_valid_graph_constructs_without_error PASSED [ 64%]
tests/test_graph_heuristic.py::test_edge_unknown_target_raises_value_error PASSED [ 64%]
tests/test_graph_heuristic.py::test_edge_unknown_source_raises_value_error PASSED [ 64%]
tests/test_graph_heuristic.py::test_duplicate_ids_raises_value_error PASSED [ 64%]
tests/test_graph_heuristic.py::test_requires_edge_pointing_to_output_raises_value_error PASSED [ 64%]
tests/test_graph_heuristic.py::test_produces_edge_pointing_to_input_raises_value_error PASSED [ 64%]
tests/test_graph_heuristic.py::test_capability_line_is_body_relative PASSED [ 65%]
tests/test_graph_heuristic.py::test_input_line_is_body_relative PASSED   [ 65%]
tests/test_graph_heuristic.py::test_core_exports_extract_graph_heuristic PASSED [ 65%]
tests/test_graph_heuristic.py::test_import_path_smoke PASSED             [ 65%]
tests/test_graph_heuristic.py::test_duplicate_allowed_tools_produce_single_input PASSED [ 65%]
tests/test_graph_parser.py::test_clean_response_parses_to_agent_graph PASSED [ 65%]
tests/test_graph_parser.py::test_clean_response_has_correct_capability_count PASSED [ 65%]
tests/test_graph_parser.py::test_clean_response_has_correct_edge_count PASSED [ 65%]
tests/test_graph_parser.py::test_extra_capabilities_response_parses_ok PASSED [ 65%]
tests/test_graph_parser.py::test_empty_collections_valid PASSED          [ 65%]
tests/test_graph_parser.py::test_strips_code_fence PASSED                [ 65%]
tests/test_graph_parser.py::test_strips_prose_preamble PASSED            [ 65%]
tests/test_graph_parser.py::test_strips_surrounding_whitespace PASSED    [ 65%]
tests/test_graph_parser.py::test_malformed_json_raises_graph_json_error PASSED [ 65%]
tests/test_graph_parser.py::test_graph_json_error_is_graph_parse_error PASSED [ 65%]
tests/test_graph_parser.py::test_graph_json_error_message_includes_preview PASSED [ 65%]
tests/test_graph_parser.py::test_schema_error_for_wrong_type PASSED      [ 66%]
tests/test_graph_parser.py::test_schema_error_is_graph_parse_error PASSED [ 66%]
tests/test_graph_parser.py::test_schema_error_for_missing_top_level_field PASSED [ 66%]
tests/test_graph_parser.py::test_schema_error_for_extra_top_level_field PASSED [ 66%]
tests/test_graph_parser.py::test_schema_error_for_capability_missing_field PASSED [ 66%]
tests/test_graph_parser.py::test_schema_error_for_invalid_input_kind PASSED [ 66%]
tests/test_graph_parser.py::test_schema_error_for_invalid_output_kind PASSED [ 66%]
tests/test_graph_parser.py::test_schema_error_for_invalid_edge_kind PASSED [ 66%]
tests/test_graph_parser.py::test_schema_error_for_bool_line_value PASSED [ 66%]
tests/test_graph_parser.py::test_bad_line_raises_graph_value_error PASSED [ 66%]
tests/test_graph_parser.py::test_graph_value_error_is_graph_parse_error PASSED [ 66%]
tests/test_graph_parser.py::test_duplicate_id_across_collections_raises_graph_value_error PASSED [ 66%]
tests/test_graph_parser.py::test_dangling_edge_raises_graph_value_error PASSED [ 66%]
tests/test_graph_parser.py::test_line_zero_is_out_of_range PASSED        [ 66%]
tests/test_graph_parser.py::test_line_equal_to_body_lines_is_valid PASSED [ 66%]
tests/test_graph_parser.py::test_capabilities_over_cap_rejected PASSED   [ 67%]
tests/test_graph_prompts.py::test_graph_agents_registry_contains_all_variants PASSED [ 67%]
tests/test_graph_prompts.py::test_get_graph_prompt_returns_claude PASSED [ 67%]
tests/test_graph_prompts.py::test_get_graph_prompt_returns_codex PASSED  [ 67%]
tests/test_graph_prompts.py::test_get_graph_prompt_returns_cursor PASSED [ 67%]
tests/test_graph_prompts.py::test_get_graph_prompt_unknown_raises_value_error PASSED [ 67%]
tests/test_graph_prompts.py::test_all_graph_agent_ids_match_registry_keys PASSED [ 67%]
tests/test_graph_prompts.py::test_claude_graph_render_contains_xml_skill_tag PASSED [ 67%]
tests/test_graph_prompts.py::test_claude_graph_render_contains_xml_schema_tag PASSED [ 67%]
tests/test_graph_prompts.py::test_claude_graph_render_contains_worked_example_tag PASSED [ 67%]
tests/test_graph_prompts.py::test_claude_graph_render_contains_skill_body PASSED [ 67%]
tests/test_graph_prompts.py::test_claude_graph_render_no_markdown_headers PASSED [ 67%]
tests/test_graph_prompts.py::test_claude_graph_render_is_deterministic PASSED [ 67%]
tests/test_graph_prompts.py::test_codex_graph_render_contains_markdown_schema_header PASSED [ 67%]
tests/test_graph_prompts.py::test_codex_graph_render_contains_markdown_skill_header PASSED [ 67%]
tests/test_graph_prompts.py::test_codex_graph_render_no_xml_tags PASSED  [ 68%]
tests/test_graph_prompts.py::test_codex_graph_render_contains_skill_body PASSED [ 68%]
tests/test_graph_prompts.py::test_codex_graph_render_is_deterministic PASSED [ 68%]
tests/test_graph_prompts.py::test_cursor_graph_render_no_xml_tags PASSED [ 68%]
tests/test_graph_prompts.py::test_cursor_graph_render_no_markdown_headers PASSED [ 68%]
tests/test_graph_prompts.py::test_cursor_graph_render_shorter_than_claude PASSED [ 68%]
tests/test_graph_prompts.py::test_cursor_graph_render_is_deterministic PASSED [ 68%]
tests/test_graph_prompts.py::test_cursor_graph_render_contains_skill_body PASSED [ 68%]
tests/test_graph_prompts.py::test_all_variants_render_different_prompts PASSED [ 68%]
tests/test_graph_prompts.py::test_all_variants_include_body_relative_line_hint PASSED [ 68%]
tests/test_graph_render.py::test_render_graph_text_includes_source PASSED [ 68%]
tests/test_graph_render.py::test_render_graph_text_section_headers PASSED [ 68%]
tests/test_graph_render.py::test_render_graph_text_capability_name_and_line PASSED [ 68%]
tests/test_graph_render.py::test_render_graph_text_capability_description PASSED [ 68%]
tests/test_graph_render.py::test_render_graph_text_input_kind PASSED     [ 68%]
tests/test_graph_render.py::test_render_graph_text_output_kind PASSED    [ 68%]
tests/test_graph_render.py::test_render_graph_text_edges PASSED          [ 69%]
tests/test_graph_render.py::test_render_graph_text_empty_graph PASSED    [ 69%]
tests/test_graph_render.py::test_render_graph_text_is_deterministic PASSED [ 69%]
tests/test_graph_render.py::test_render_graph_json_is_valid_json PASSED  [ 69%]
tests/test_graph_render.py::test_render_graph_json_top_level_keys PASSED [ 69%]
tests/test_graph_render.py::test_render_graph_json_source PASSED         [ 69%]
tests/test_graph_render.py::test_render_graph_json_capability_structure PASSED [ 69%]
tests/test_graph_render.py::test_render_graph_json_input_count PASSED    [ 69%]
tests/test_graph_render.py::test_render_graph_json_output_count PASSED   [ 69%]
tests/test_graph_render.py::test_render_graph_json_edge_structure PASSED [ 69%]
tests/test_graph_render.py::test_render_graph_json_edge_kinds PASSED     [ 69%]
tests/test_graph_render.py::test_render_graph_json_is_deterministic PASSED [ 69%]
tests/test_graph_render.py::test_render_graph_json_round_trip_ids PASSED [ 69%]
tests/test_graph_render.py::test_render_graph_json_empty_graph PASSED    [ 69%]
tests/test_graph_render.py::test_render_graph_json_null_line_is_serialised PASSED [ 69%]
tests/test_history_io.py::test_load_returns_none_for_missing_file PASSED [ 70%]
tests/test_history_io.py::test_load_raises_on_malformed_json PASSED      [ 70%]
tests/test_history_io.py::test_load_raises_on_missing_top_level_field PASSED [ 70%]
tests/test_history_io.py::test_load_raises_error_includes_path PASSED    [ 70%]
tests/test_history_io.py::test_load_from_fixture_one_run PASSED          [ 70%]
tests/test_history_io.py::test_load_from_fixture_multi_run PASSED        [ 70%]
tests/test_history_io.py::test_load_from_fixture_malformed_raises PASSED [ 70%]
tests/test_history_io.py::test_load_raises_when_root_is_not_object PASSED [ 70%]
tests/test_history_io.py::test_load_raises_when_runs_is_not_a_list PASSED [ 70%]
tests/test_history_io.py::test_load_raises_on_schema_version_mismatch PASSED [ 70%]
tests/test_history_io.py::test_load_raises_on_malformed_run_entry PASSED [ 70%]
tests/test_history_io.py::test_save_writes_valid_json PASSED             [ 70%]
tests/test_history_io.py::test_load_preserves_other_writers_temporary_files PASSED [ 70%]
tests/test_history_io.py::test_save_atomic_original_intact_on_failure PASSED [ 70%]
tests/test_history_io.py::test_save_field_order_matches_schema PASSED    [ 70%]
tests/test_history_io.py::test_append_run_initializes_new_ledger PASSED  [ 71%]
tests/test_history_io.py::test_append_run_preserves_prior_runs PASSED    [ 71%]
tests/test_history_io.py::test_append_run_mismatched_skill_path_raises PASSED [ 71%]
tests/test_history_model.py::test_hash_is_16_hex_chars PASSED            [ 71%]
tests/test_history_model.py::test_hash_is_deterministic PASSED           [ 71%]
tests/test_history_model.py::test_hash_differs_with_different_content PASSED [ 71%]
tests/test_history_model.py::test_hash_is_lowercase PASSED               [ 71%]
tests/test_history_model.py::test_build_entry_timestamp_format PASSED    [ 71%]
tests/test_history_model.py::test_build_entry_timestamp_no_microseconds PASSED [ 71%]
tests/test_history_model.py::test_build_entry_uses_injected_now PASSED   [ 71%]
tests/test_history_model.py::test_build_entry_counts_diagnostics PASSED  [ 71%]
tests/test_history_model.py::test_build_entry_valid_reflects_result PASSED [ 71%]
tests/test_history_model.py::test_build_entry_version_recorded PASSED    [ 71%]
tests/test_history_model.py::test_build_entry_hash_matches_skill PASSED  [ 71%]
tests/test_history_model.py::test_ledger_entry_is_frozen PASSED          [ 71%]
tests/test_history_model.py::test_ledger_is_frozen PASSED                [ 71%]
tests/test_history_model.py::test_result_counts_is_frozen PASSED         [ 72%]
tests/test_history_model.py::test_validation_modes_is_frozen PASSED      [ 72%]
tests/test_history_model.py::test_ledger_entry_is_hashable PASSED        [ 72%]
tests/test_history_model.py::test_ledger_is_hashable PASSED              [ 72%]
tests/test_history_model.py::test_ledger_path_for_is_outside_bundle PASSED [ 72%]
tests/test_history_model.py::test_ledger_path_for_is_pure PASSED         [ 72%]
tests/test_history_model.py::test_round_trip_single_entry PASSED         [ 72%]
tests/test_history_model.py::test_round_trip_multiple_entries PASSED     [ 72%]
tests/test_history_model.py::test_round_trip_with_agent_fields PASSED    [ 72%]
tests/test_history_regression.py::test_no_prior_runs_returns_empty PASSED [ 72%]
tests/test_history_regression.py::test_prior_passing_same_hash_current_failing_emits_warning PASSED [ 72%]
tests/test_history_regression.py::test_prior_passing_same_hash_current_passing_returns_empty PASSED [ 72%]
tests/test_history_regression.py::test_prior_failing_same_hash_current_failing_returns_empty PASSED [ 72%]
tests/test_history_regression.py::test_prior_passing_different_hash_returns_empty PASSED [ 72%]
tests/test_history_regression.py::test_multiple_matching_priors_emits_one_warning_with_most_recent PASSED [ 72%]
tests/test_history_regression.py::test_regression_message_includes_result_counts PASSED [ 73%]
tests/test_history_regression.py::test_recovery_does_not_trigger_regression PASSED [ 73%]
tests/test_ingest_sanitization.py::test_sanitize_escapes_ansi_escape_char PASSED [ 73%]
tests/test_ingest_sanitization.py::test_sanitize_escapes_newlines_and_tabs PASSED [ 73%]
tests/test_ingest_sanitization.py::test_sanitize_leaves_normal_text_unchanged PASSED [ 73%]
tests/test_ingest_sanitization.py::test_ingested_critique_preserves_machine_data_and_escapes_display PASSED [ 73%]
tests/test_ingest_sanitization.py::test_graph_text_render_escapes_node_names PASSED [ 73%]
tests/test_ingest_sanitization.py::test_graph_json_render_stays_safe_and_raw PASSED [ 73%]
tests/test_io_limits.py::test_file_over_the_cap_raises_the_callers_error_type PASSED [ 73%]
tests/test_io_limits.py::test_file_exactly_at_the_cap_is_accepted PASSED [ 73%]
tests/test_io_limits.py::test_empty_file_is_accepted PASSED              [ 73%]
tests/test_io_limits.py::test_missing_file_defers_to_the_caller PASSED   [ 73%]
tests/test_io_limits.py::test_caps_are_ordered_by_how_large_each_file_legitimately_gets PASSED [ 73%]
tests/test_io_limits.py::test_oversized_skill_is_refused_by_bounded_read PASSED [ 73%]
tests/test_io_limits.py::test_normal_skill_still_parses PASSED           [ 73%]
tests/test_io_limits.py::test_oversized_ledger_is_refused PASSED         [ 74%]
tests/test_io_limits.py::test_oversized_config_is_refused PASSED         [ 74%]
tests/test_io_limits.py::test_normal_config_still_loads PASSED           [ 74%]
tests/test_io_limits.py::test_missing_ledger_still_returns_none PASSED   [ 74%]
tests/test_measure_token_error.py::test_heuristic_matches_estimate_tokens_when_tiktoken_is_absent PASSED [ 74%]
tests/test_measure_token_error.py::test_naive_is_the_chars_over_four_rule PASSED [ 74%]
tests/test_measure_token_error.py::test_percentile_picks_the_nearest_rank PASSED [ 74%]
tests/test_measure_token_error.py::test_percentile_handles_a_single_sample_and_none PASSED [ 74%]
tests/test_measure_token_error.py::test_percentile_never_indexes_out_of_range PASSED [ 74%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--activation-hypotheses+--agent-reason] PASSED [ 74%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--activation-hypotheses+--analyze-graph] PASSED [ 74%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--activation-hypotheses+--emit-critique-prompt] PASSED [ 74%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--activation-hypotheses+--emit-graph] PASSED [ 74%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--activation-hypotheses+--emit-graph-prompt] PASSED [ 74%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--activation-hypotheses+--history] PASSED [ 74%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--activation-hypotheses+--ingest-critique] PASSED [ 74%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--activation-hypotheses+--ingest-graph] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--activation-hypotheses+--show-history] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--agent-reason+--analyze-graph] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--agent-reason+--emit-critique-prompt] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--agent-reason+--emit-graph] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--agent-reason+--emit-graph-prompt] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--agent-reason+--history] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--agent-reason+--ingest-critique] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--agent-reason+--ingest-graph] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--agent-reason+--show-history] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--analyze-graph+--emit-critique-prompt] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--analyze-graph+--emit-graph] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--analyze-graph+--emit-graph-prompt] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--analyze-graph+--history] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--analyze-graph+--ingest-critique] PASSED [ 75%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--analyze-graph+--ingest-graph] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--analyze-graph+--show-history] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-critique-prompt+--emit-graph] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-critique-prompt+--emit-graph-prompt] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-critique-prompt+--history] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-critique-prompt+--ingest-critique] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-critique-prompt+--ingest-graph] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-critique-prompt+--show-history] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-graph+--emit-graph-prompt] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-graph+--history] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-graph+--ingest-critique] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-graph+--ingest-graph] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-graph+--show-history] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-graph-prompt+--history] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-graph-prompt+--ingest-critique] PASSED [ 76%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-graph-prompt+--ingest-graph] PASSED [ 77%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--emit-graph-prompt+--show-history] PASSED [ 77%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--history+--ingest-critique] PASSED [ 77%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--history+--ingest-graph] PASSED [ 77%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--history+--show-history] PASSED [ 77%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--ingest-critique+--ingest-graph] PASSED [ 77%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--ingest-critique+--show-history] PASSED [ 77%]
tests/test_mode_conflicts.py::test_pair_matches_captured_behavior[--ingest-graph+--show-history] PASSED [ 77%]
tests/test_mode_conflicts.py::test_fixture_covers_every_pair_of_mode_flags PASSED [ 77%]
tests/test_mode_conflicts.py::test_activation_fragments_cover_every_declared_flag PASSED [ 77%]
tests/test_mode_conflicts.py::test_conflicts_are_symmetric PASSED        [ 77%]
tests/test_mode_conflicts.py::test_no_unordered_pair_is_declared_twice PASSED [ 77%]
tests/test_mode_conflicts.py::test_every_conflict_names_a_declared_flag PASSED [ 77%]
tests/test_mode_conflicts.py::test_every_conflict_reason_names_both_flags PASSED [ 77%]
tests/test_mode_conflicts.py::test_every_mode_flag_resolves_on_the_parser PASSED [ 77%]
tests/test_mode_conflicts.py::test_every_mode_flag_is_in_a_known_group PASSED [ 77%]
tests/test_mode_conflicts.py::test_suppression_targets_are_declared_flags PASSED [ 78%]
tests/test_mode_conflicts.py::test_agent_reason_is_an_emit_mode_on_its_own PASSED [ 78%]
tests/test_mode_conflicts.py::test_agent_reason_stops_being_an_emit_mode_with_an_ingest_flag[--ingest-critique] PASSED [ 78%]
tests/test_mode_conflicts.py::test_agent_reason_stops_being_an_emit_mode_with_an_ingest_flag[--ingest-graph] PASSED [ 78%]
tests/test_mode_conflicts.py::test_cli_still_exits_two_and_prints_the_message PASSED [ 78%]
tests/test_mode_conflicts.py::test_cli_reports_the_multi_emit_case_before_the_pairwise_table PASSED [ 78%]
tests/test_name_compliance.py::test_rejects_leading_hyphen PASSED        [ 78%]
tests/test_name_compliance.py::test_rejects_trailing_hyphen PASSED       [ 78%]
tests/test_name_compliance.py::test_rejects_both_leading_and_trailing_hyphen PASSED [ 78%]
tests/test_name_compliance.py::test_accepts_valid_name_no_edge_hyphens PASSED [ 78%]
tests/test_name_compliance.py::test_leading_trailing_skips_missing_name PASSED [ 78%]
tests/test_name_compliance.py::test_rejects_consecutive_hyphens PASSED   [ 78%]
tests/test_name_compliance.py::test_accepts_single_hyphens PASSED        [ 78%]
tests/test_name_compliance.py::test_consecutive_skips_missing_name PASSED [ 78%]
tests/test_name_compliance.py::test_directory_mismatch_fires_when_different PASSED [ 78%]
tests/test_name_compliance.py::test_directory_match_passes_when_matching PASSED [ 79%]
tests/test_name_compliance.py::test_directory_match_skips_missing_name PASSED [ 79%]
tests/test_neutral_import.py::test_neutral_import_preserves_source_unknowns_and_assigns_importer_identity PASSED [ 79%]
tests/test_neutral_import.py::test_invalid_neutral_imports_leave_no_partial_store[overflow] PASSED [ 79%]
tests/test_neutral_import.py::test_invalid_neutral_imports_leave_no_partial_store[duplicate] PASSED [ 79%]
tests/test_neutral_import.py::test_invalid_neutral_imports_leave_no_partial_store[oversized] PASSED [ 79%]
tests/test_neutral_import.py::test_invalid_neutral_imports_leave_no_partial_store[second-invalid] PASSED [ 79%]
tests/test_neutral_import.py::test_invalid_neutral_imports_leave_no_partial_store[binding] PASSED [ 79%]
tests/test_neutral_import.py::test_invalid_neutral_imports_leave_no_partial_store[wrong-bundle] PASSED [ 79%]
tests/test_neutral_import.py::test_invalid_neutral_imports_leave_no_partial_store[version] PASSED [ 79%]
tests/test_neutral_import.py::test_invalid_neutral_imports_leave_no_partial_store[empty] PASSED [ 79%]
tests/test_neutral_import.py::test_invalid_neutral_imports_leave_no_partial_store[code] PASSED [ 79%]
tests/test_neutral_import.py::test_invalid_neutral_imports_leave_no_partial_store[bad-source-identity] PASSED [ 79%]
tests/test_observed_execution.py::test_runner_record_passes_the_gate_only_after_import_and_trusted_approval PASSED [ 79%]
tests/test_observed_execution.py::test_runner_records_a_failed_check_and_an_unstartable_command PASSED [ 79%]
tests/test_observed_execution.py::test_runner_refuses_to_write_into_the_bundle PASSED [ 80%]
tests/test_observed_execution.py::test_static_evidence_passes_by_default_and_is_unknown_when_observed_execution_is_required PASSED [ 80%]
tests/test_observed_execution.py::test_requiring_observed_execution_does_not_soften_failures_or_touch_optional_checks PASSED [ 80%]
tests/test_observed_execution.py::test_adapter_rejects_records_that_are_not_observed_executions PASSED [ 80%]
tests/test_observed_execution.py::test_schema_runner_and_adapter_agree_on_the_record_fields PASSED [ 80%]
tests/test_onboarding.py::test_first_use_text_and_json_contracts[hello/SKILL.md-False-0-None-None] PASSED [ 80%]
tests/test_onboarding.py::test_first_use_text_and_json_contracts[invalid/SKILL.md-False-1-parse.error-3] PASSED [ 80%]
tests/test_onboarding.py::test_first_use_text_and_json_contracts[missing/SKILL.md-False-1-references.broken-link-6] PASSED [ 80%]
tests/test_onboarding.py::test_first_use_text_and_json_contracts[hello/-False-0-None-None] PASSED [ 80%]
tests/test_onboarding.py::test_first_use_text_and_json_contracts[warning/SKILL.md-False-0-frontmatter.field.unknown-4] PASSED [ 80%]
tests/test_onboarding.py::test_first_use_text_and_json_contracts[warning/SKILL.md-True-1-frontmatter.field.unknown-4] PASSED [ 80%]
tests/test_onboarding.py::test_readme_and_help_put_basic_validation_first PASSED [ 80%]
tests/test_onboarding.py::test_neutral_export_example_runs_real_validation PASSED [ 80%]
tests/test_parser.py::test_parses_valid_frontmatter PASSED               [ 80%]
tests/test_parser.py::test_parses_body_content PASSED                    [ 80%]
tests/test_parser.py::test_body_does_not_contain_frontmatter_delimiters PASSED [ 80%]
tests/test_parser.py::test_raw_text_contains_full_file PASSED            [ 81%]
tests/test_parser.py::test_body_lines_counts_only_body PASSED            [ 81%]
tests/test_parser.py::test_handles_missing_frontmatter PASSED            [ 81%]
tests/test_parser.py::test_handles_file_with_all_known_fields PASSED     [ 81%]
tests/test_parser.py::test_path_is_preserved PASSED                      [ 81%]
tests/test_parser.py::test_raises_parse_error_for_non_utf8 PASSED        [ 81%]
tests/test_parser.py::test_handles_bom_prefixed_file PASSED              [ 81%]
tests/test_parser.py::test_rejects_string_frontmatter PASSED             [ 81%]
tests/test_parser.py::test_rejects_list_frontmatter PASSED               [ 81%]
tests/test_parser.py::test_rejects_int_frontmatter PASSED                [ 81%]
tests/test_parser.py::test_empty_frontmatter_is_recognized PASSED        [ 81%]
tests/test_pre_commit.py::test_pre_commit_pass PASSED                    [ 81%]
tests/test_pre_commit.py::test_pre_commit_fail PASSED                    [ 81%]
tests/test_profile_freshness.py::test_shipped_registry_matches_the_advisory_profile_provenance PASSED [ 81%]
tests/test_profile_freshness.py::test_profile_older_than_the_limit_is_reported_and_one_at_the_limit_is_not PASSED [ 81%]
tests/test_profile_freshness.py::test_newer_docs_page_is_reported_even_when_the_entry_is_recent PASSED [ 82%]
tests/test_profile_freshness.py::test_unchecked_docs_page_is_reported_rather_than_treated_as_fresh PASSED [ 82%]
tests/test_profile_freshness.py::test_docs_check_sends_only_head_requests PASSED [ 82%]
tests/test_profile_freshness.py::test_cli_freshness_warnings_leave_the_report_and_exit_code_unchanged PASSED [ 82%]
tests/test_profile_freshness.py::test_cli_freshness_check_is_scoped_by_target_agent PASSED [ 82%]
tests/test_profile_freshness.py::test_malformed_registry_is_rejected_with_the_field_to_fix[schema_version = 2\n[agents.claude]\n-schema_version = 1] PASSED [ 82%]
tests/test_profile_freshness.py::test_malformed_registry_is_rejected_with_the_field_to_fix[schema_version = 1\n-at least one] PASSED [ 82%]
tests/test_profile_freshness.py::test_malformed_registry_is_rejected_with_the_field_to_fix[schema_version = 1\n[agents.claude]\nversion = "1"\n-must contain exactly] PASSED [ 82%]
tests/test_profile_freshness.py::test_malformed_registry_is_rejected_with_the_field_to_fix[schema_version = 1\n[agents.claude]\nversion = "1.2.3"\nchecked = "https://example.invalid/releases/1.2.3"\nverified_on = "2026-04-20"\ndocs_url = "https://example.invalid"\nconfirmed = ["compat.claude-only"]\ncontradicted = []\n-TOML date] PASSED [ 82%]
tests/test_profile_freshness.py::test_malformed_registry_is_rejected_with_the_field_to_fix[schema_version = 1\n[agents.claude]\nversion = "1.2.3"\nchecked = "https://example.invalid/releases/1.2.3"\nverified_on = 2026-04-20\ndocs_url = "file:///etc/hostname"\nconfirmed = ["compat.claude-only"]\ncontradicted = []\n-http or https] PASSED [ 82%]
tests/test_profile_freshness.py::test_malformed_registry_is_rejected_with_the_field_to_fix[schema_version = 1\n[agents.claude]\nversion = ""\nchecked = "https://example.invalid/releases/1.2.3"\nverified_on = 2026-04-20\ndocs_url = "https://example.invalid"\nconfirmed = ["compat.claude-only"]\ncontradicted = []\n-version must be a nonempty string] PASSED [ 82%]
tests/test_profile_freshness.py::test_malformed_registry_is_rejected_with_the_field_to_fix[schema_version = 1\n[agents.claude]\nversion = "1.2.3"\nchecked = "https://example.invalid/releases/1.2.3"\nverified_on = 2026-04-20\ndocs_url = "https://example.invalid"\nconfirmed = ["compat.claude-only"]\ncontradicted = "none"\n-array of rule IDs] PASSED [ 82%]
tests/test_profile_freshness.py::test_malformed_registry_is_rejected_with_the_field_to_fix[schema_version = [1\n-not valid TOML] PASSED [ 82%]
tests/test_profile_freshness.py::test_cli_rejects_a_malformed_registry_and_orphaned_freshness_options PASSED [ 82%]
tests/test_promptfoo_current.py::test_fixture_bytes_match_recorded_provenance PASSED [ 82%]
tests/test_promptfoo_current.py::test_actual_current_exports_import_through_cli[export.json-states0] PASSED [ 82%]
tests/test_promptfoo_current.py::test_actual_current_exports_import_through_cli[error-export.json-states1] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[version] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[schema] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[unknown-shape] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[missing-id] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[grading-conflict] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[grading-components] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[failure-type] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[failure-conflict] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[token-usage] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[runtime] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[vars] PASSED [ 83%]
tests/test_promptfoo_current.py::test_malformed_unbound_rows_and_unsupported_contracts_fail_without_writes[overflow] PASSED [ 83%]
tests/test_promptfoo_current.py::test_partial_grading_and_missing_model_identity_are_not_invented PASSED [ 83%]
tests/test_published_schemas.py::test_schemas_are_valid_json PASSED      [ 83%]
tests/test_published_schemas.py::test_critique_schema_required_matches_parser PASSED [ 84%]
tests/test_published_schemas.py::test_critique_schema_severity_enum_matches_parser PASSED [ 84%]
tests/test_published_schemas.py::test_critique_schema_scores_are_0_to_100 PASSED [ 84%]
tests/test_published_schemas.py::test_graph_schema_required_matches_parser PASSED [ 84%]
tests/test_published_schemas.py::test_graph_schema_kind_enums_match_parser PASSED [ 84%]
tests/test_published_schemas.py::test_critique_schema_forbids_additional_properties PASSED [ 84%]
tests/test_published_schemas.py::test_graph_schema_forbids_additional_properties PASSED [ 84%]
tests/test_published_schemas.py::test_schemas_validate_known_good_fixtures PASSED [ 84%]
tests/test_readme_test_count_claim.py::test_ledger_test_count_matches_collected_count PASSED [ 84%]
tests/test_references.py::test_extracts_markdown_links PASSED            [ 84%]
tests/test_references.py::test_extracts_image_links PASSED               [ 84%]
tests/test_references.py::test_ignores_urls PASSED                       [ 84%]
tests/test_references.py::test_extracts_directive_references PASSED      [ 84%]
tests/test_references.py::test_deduplicates_references PASSED            [ 84%]
tests/test_references.py::test_extracts_backtick_paths_with_separator PASSED [ 84%]
tests/test_references.py::test_backtick_skips_code_block_content PASSED  [ 85%]
tests/test_references.py::test_extracts_html_anchor_hrefs PASSED         [ 85%]
tests/test_references.py::test_empty_body_returns_no_refs PASSED         [ 85%]
tests/test_references.py::test_depth_same_directory PASSED               [ 85%]
tests/test_references.py::test_depth_one_level PASSED                    [ 85%]
tests/test_references.py::test_depth_two_levels PASSED                   [ 85%]
tests/test_references.py::test_depth_parent_traversal PASSED             [ 85%]
tests/test_references.py::test_broken_ref_detected PASSED                [ 85%]
tests/test_references.py::test_valid_ref_passes PASSED                   [ 85%]
tests/test_references.py::test_no_refs_passes PASSED                     [ 85%]
tests/test_references.py::test_tilde_ref_expands_to_home PASSED          [ 85%]
tests/test_references.py::test_tilde_ref_missing_still_reported PASSED   [ 85%]
tests/test_references.py::test_tilde_ref_outside_skill_tree_still_escape PASSED [ 85%]
tests/test_references.py::test_directory_nesting_is_not_reference_depth PASSED [ 85%]
tests/test_references.py::test_parent_traversal_flagged PASSED           [ 85%]
tests/test_references.py::test_single_dotdot_traversal_flagged PASSED    [ 85%]
tests/test_references.py::test_shallow_ref_passes PASSED                 [ 86%]
tests/test_references.py::test_no_refs_no_depth_issues PASSED            [ 86%]
tests/test_references.py::test_symlink_escape_detected PASSED            [ 86%]
tests/test_references.py::test_dotdot_escape_detected PASSED             [ 86%]
tests/test_references.py::test_symlink_within_skill_dir_passes PASSED    [ 86%]
tests/test_self_host.py::test_self_host_symbolic_clean PASSED            [ 86%]
tests/test_self_host.py::test_self_host_graph_analyzers_clean PASSED     [ 86%]
tests/test_self_host.py::test_self_host_critique_clean PASSED            [ 86%]
tests/test_self_host.py::test_self_host_graph_agent_clean PASSED         [ 86%]
tests/test_self_host.py::test_self_host_full_pipeline_clean PASSED       [ 86%]
tests/test_self_host.py::test_self_host_history_round_trip PASSED        [ 86%]
tests/test_self_host.py::test_self_host_description_score_above_threshold PASSED [ 86%]
tests/test_semantic_bridge.py::test_render_critique_prompt_non_empty PASSED [ 86%]
tests/test_semantic_bridge.py::test_render_critique_prompt_contains_skill_body PASSED [ 86%]
tests/test_semantic_bridge.py::test_render_critique_prompt_contains_skill_name PASSED [ 86%]
tests/test_semantic_bridge.py::test_render_critique_prompt_contains_schema_fields PASSED [ 87%]
tests/test_semantic_bridge.py::test_score_at_warning_threshold_boundary_below PASSED [ 87%]
tests/test_semantic_bridge.py::test_score_at_warning_threshold_boundary_at PASSED [ 87%]
tests/test_semantic_bridge.py::test_score_at_info_threshold_boundary_below PASSED [ 87%]
tests/test_semantic_bridge.py::test_score_at_info_threshold_boundary_at PASSED [ 87%]
tests/test_semantic_bridge.py::test_all_scores_healthy_produces_no_score_diagnostics PASSED [ 87%]
tests/test_semantic_bridge.py::test_completeness_score_produces_diagnostic PASSED [ 87%]
tests/test_semantic_bridge.py::test_executability_score_produces_diagnostic PASSED [ 87%]
tests/test_semantic_bridge.py::test_missing_context_produces_one_warning_per_item PASSED [ 87%]
tests/test_semantic_bridge.py::test_missing_context_message_contains_flag_text PASSED [ 87%]
tests/test_semantic_bridge.py::test_empty_missing_context_produces_no_diagnostics PASSED [ 87%]
tests/test_semantic_bridge.py::test_contradiction_produces_error_diagnostic PASSED [ 87%]
tests/test_semantic_bridge.py::test_contradiction_message_contains_both_locations PASSED [ 87%]
tests/test_semantic_bridge.py::test_multiple_contradictions_produce_multiple_errors PASSED [ 87%]
tests/test_semantic_bridge.py::test_finding_severity_inherited PASSED    [ 87%]
tests/test_semantic_bridge.py::test_finding_message_contains_section_and_suggestion PASSED [ 88%]
tests/test_semantic_bridge.py::test_find_section_line_known_section PASSED [ 88%]
tests/test_semantic_bridge.py::test_find_section_line_unknown_section_returns_none PASSED [ 88%]
tests/test_semantic_bridge.py::test_find_section_line_case_insensitive PASSED [ 88%]
tests/test_semantic_bridge.py::test_finding_with_known_section_has_line_number PASSED [ 88%]
tests/test_semantic_bridge.py::test_finding_with_unknown_section_has_no_line PASSED [ 88%]
tests/test_semantic_bridge.py::test_merge_errors_only_critique_on_passing_symbolic_yields_invalid PASSED [ 88%]
tests/test_semantic_bridge.py::test_merge_warnings_only_critique_on_passing_symbolic_stays_valid PASSED [ 88%]
tests/test_semantic_bridge.py::test_merge_combines_all_diagnostics PASSED [ 88%]
tests/test_semantic_bridge.py::test_merge_does_not_mutate_original PASSED [ 88%]
tests/test_semantic_bridge.py::test_merge_preserves_path PASSED          [ 88%]
tests/test_semantic_bridge.py::test_response_clean_produces_no_diagnostics PASSED [ 88%]
tests/test_semantic_bridge.py::test_response_warnings_produces_warnings PASSED [ 88%]
tests/test_semantic_bridge.py::test_response_contradiction_produces_error PASSED [ 88%]
tests/test_semantic_bridge.py::test_response_findings_mixed_has_all_severities PASSED [ 88%]
tests/test_semantic_bridge.py::test_find_section_line_is_body_relative PASSED [ 88%]
tests/test_semantic_bridge.py::test_finding_diagnostic_line_is_body_relative_not_file_relative PASSED [ 89%]
tests/test_setext_dependencies.py::test_setext_helper_change_blocks_trusted_reuse[=] PASSED [ 89%]
tests/test_setext_dependencies.py::test_setext_helper_change_blocks_trusted_reuse[==] PASSED [ 89%]
tests/test_setext_dependencies.py::test_setext_helper_change_blocks_trusted_reuse[======] PASSED [ 89%]
tests/test_setext_dependencies.py::test_setext_helper_change_blocks_trusted_reuse[-] PASSED [ 89%]
tests/test_setext_dependencies.py::test_setext_helper_change_blocks_trusted_reuse[--] PASSED [ 89%]
tests/test_setext_dependencies.py::test_setext_helper_change_blocks_trusted_reuse[---] PASSED [ 89%]
tests/test_setext_dependencies.py::test_setext_helper_change_blocks_trusted_reuse[------] PASSED [ 89%]
tests/test_setext_dependencies.py::test_setext_helper_change_blocks_trusted_reuse[   == \t] PASSED [ 89%]
tests/test_setext_dependencies.py::test_setext_helper_change_blocks_trusted_reuse[  --\t ] PASSED [ 89%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[- `Title\n  ==\n  [helper](helper.py) `] PASSED [ 89%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[1. `Title\n   --\n   [helper](helper.py) `] PASSED [ 89%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[- Steps:\n    - `Title\n      ==\n      [helper](helper.py) `] PASSED [ 89%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[-\t`Title\n\t==\n\t[helper](helper.py) `] PASSED [ 89%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[   # `Title\n[helper](helper.py) `] PASSED [ 89%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[`Before\n   # Heading\n[helper](helper.py) `] PASSED [ 90%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[`Before\n_ _ _\n[helper](helper.py) `] PASSED [ 90%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[`Before\n  * * * \t\n[helper](helper.py) `] PASSED [ 90%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[`Before\n- - -\n[helper](helper.py) `] PASSED [ 90%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[`Title\nsecond line\n==\n[helper](helper.py) `] PASSED [ 90%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[`Before\n\nTitle\n==\n[helper](helper.py) `] PASSED [ 90%]
tests/test_setext_dependencies.py::test_adjacent_blocks_keep_governed_helper[`First\n==\nSecond\n--\n[helper](helper.py) `] PASSED [ 90%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[-=] PASSED [ 90%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[--] PASSED [ 90%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[---] PASSED [ 90%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[----] PASSED [ 90%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[-   ===\t] PASSED [ 90%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[- -=] PASSED [ 90%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[- --] PASSED [ 90%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[- ---] PASSED [ 90%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[- ----] PASSED [ 91%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[- -   ===\t] PASSED [ 91%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[1. -=] PASSED [ 91%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[1. --] PASSED [ 91%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[1. ---] PASSED [ 91%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[1. ----] PASSED [ 91%]
tests/test_setext_dependencies.py::test_multiline_heading_code_span_stays_intact[1. -   ===\t] PASSED [ 91%]
tests/test_setext_dependencies.py::test_non_boundaries_preserve_paragraph_code_spans[    ==] PASSED [ 91%]
tests/test_setext_dependencies.py::test_non_boundaries_preserve_paragraph_code_spans[\t==] PASSED [ 91%]
tests/test_setext_dependencies.py::test_non_boundaries_preserve_paragraph_code_spans[= =] PASSED [ 91%]
tests/test_setext_dependencies.py::test_non_boundaries_preserve_paragraph_code_spans[== text] PASSED [ 91%]
tests/test_setext_dependencies.py::test_non_boundaries_preserve_paragraph_code_spans[\\==] PASSED [ 91%]
tests/test_setext_dependencies.py::test_non_boundaries_preserve_paragraph_code_spans[-_] PASSED [ 91%]
tests/test_setext_dependencies.py::test_non_boundaries_preserve_paragraph_code_spans[#not-heading] PASSED [ 91%]
tests/test_setext_dependencies.py::test_heading_code_examples_do_not_govern_helper[```md\n`Title\n==\n[example](missing.py) `\n```] PASSED [ 91%]
tests/test_setext_dependencies.py::test_heading_code_examples_do_not_govern_helper[~~~md\n`Title\n--\n[example](missing.py) `\n~~~] PASSED [ 91%]
tests/test_setext_dependencies.py::test_heading_code_examples_do_not_govern_helper[    `Title\n    ==\n    [example](missing.py) `] PASSED [ 92%]
tests/test_setext_dependencies.py::test_heading_code_examples_do_not_govern_helper[- Examples:\n\n      `Title\n      --\n      [example](missing.py) `] PASSED [ 92%]
tests/test_setext_dependencies.py::test_heading_code_examples_do_not_govern_helper[- ```md\n  `Title\n  ==\n  [example](missing.py) `\n  ```] PASSED [ 92%]
tests/test_setext_dependencies.py::test_heading_code_examples_do_not_govern_helper[`Example\n[example](missing.py) `\n==] PASSED [ 92%]
tests/test_setext_dependencies.py::test_heading_code_examples_do_not_govern_helper[Title\n==\n    [example](missing.py)] PASSED [ 92%]
tests/test_setext_dependencies.py::test_unmatched_heading_delimiters_keep_source_locations[`Title\n==\n[helper](helper.py) ``] PASSED [ 92%]
tests/test_setext_dependencies.py::test_unmatched_heading_delimiters_keep_source_locations[``Title\n--\n[helper](helper.py) `] PASSED [ 92%]
tests/test_setext_dependencies.py::test_unmatched_heading_delimiters_keep_source_locations[`Title\n==\n[helper](helper.py)] PASSED [ 92%]
tests/test_setext_dependencies.py::test_unmatched_heading_delimiters_keep_source_locations[`Title\n[helper](helper.py)\n==] PASSED [ 92%]
tests/test_setext_dependencies.py::test_unmatched_heading_delimiters_keep_source_locations[==\n[helper](helper.py)] PASSED [ 92%]
tests/test_setext_dependencies.py::test_unsupported_heading_containers_cannot_authorize_reuse[> `Title\n> ==\n> [helper](helper.py) `-False] PASSED [ 92%]
tests/test_setext_dependencies.py::test_unsupported_heading_containers_cannot_authorize_reuse[- `Title\n==\n[helper](helper.py) `-True] PASSED [ 92%]
tests/test_signatures.py::test_required_signer_accepts_a_record_signed_by_that_key PASSED [ 92%]
tests/test_signatures.py::test_required_signer_rejects_unsigned_foreign_and_altered_signatures PASSED [ 92%]
tests/test_signatures.py::test_signature_covers_canonical_bytes_not_file_formatting PASSED [ 92%]
tests/test_signatures.py::test_policy_without_required_signers_ignores_sidecars PASSED [ 93%]
tests/test_signatures.py::test_signature_never_replaces_digest_approval PASSED [ 93%]
tests/test_signatures.py::test_malformed_signer_policy_is_rejected[required_signers=[]-1 to 100 public keys] PASSED [ 93%]
tests/test_signatures.py::test_malformed_signer_policy_is_rejected[required_signers=["owner@example.invalid"]-OpenSSH public key] PASSED [ 93%]
tests/test_signatures.py::test_malformed_signer_policy_is_rejected[required_signers="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGtq0000000000000000000000000000000000000000"-1 to 100 public keys] PASSED [ 93%]
tests/test_signatures.py::test_malformed_signer_policy_is_rejected[signers=["x"]-only optional key] PASSED [ 93%]
tests/test_signatures.py::test_signer_key_keeps_key_material_and_drops_comments PASSED [ 93%]
tests/test_signatures.py::test_missing_verification_tool_is_an_error_not_a_rejection PASSED [ 93%]
tests/test_signatures.py::test_minisign_signature_is_accepted_only_from_a_required_key SKIPPED [ 93%]
tests/test_sizing.py::test_line_count_warns_for_long_body PASSED         [ 93%]
tests/test_sizing.py::test_line_count_passes_for_short_body PASSED       [ 93%]
tests/test_sizing.py::test_line_count_respects_custom_threshold PASSED   [ 93%]
tests/test_sizing.py::test_line_count_passes_at_exact_threshold PASSED   [ 93%]
tests/test_sizing.py::test_token_estimate_warns_when_exceeded PASSED     [ 93%]
tests/test_sizing.py::test_token_estimate_passes_for_normal_file PASSED  [ 93%]
tests/test_sizing.py::test_token_estimate_is_positive PASSED             [ 94%]
tests/test_sizing.py::test_token_estimate_grows_with_content PASSED      [ 94%]
tests/test_sizing.py::test_token_estimate_counts_punctuation_runs PASSED [ 94%]
tests/test_sizing.py::test_token_estimate_within_reasonable_bound PASSED [ 94%]
tests/test_template_detection.py::test_bracketed_acronyms_are_not_template PASSED [ 94%]
tests/test_template_detection.py::test_literal_ellipsis_placeholder_is_template PASSED [ 94%]
tests/test_tokenizer.py::test_tokenizer_returns_positive PASSED          [ 94%]
tests/test_tokenizer.py::test_tokenizer_consistent_across_calls PASSED   [ 94%]
tests/test_tokenizer.py::test_tiktoken_enc_cached PASSED                 [ 94%]
tests/test_tokenizer.py::test_empty_string_returns_one PASSED            [ 94%]
tests/test_tokenizer.py::test_tokenizer_concurrent_first_init_is_consistent PASSED [ 94%]
tests/test_type_annotations.py::test_make_min_score_rule_returns_callable PASSED [ 94%]
tests/test_type_annotations.py::test_make_strict_vscode_rule_returns_callable PASSED [ 94%]
tests/test_untrusted_input.py::test_valid_utf8_within_the_cap_is_returned PASSED [ 94%]
tests/test_untrusted_input.py::test_crlf_is_normalized_like_read_text_did PASSED [ 94%]
tests/test_untrusted_input.py::test_lone_carriage_return_is_also_normalized PASSED [ 94%]
tests/test_untrusted_input.py::test_file_exactly_at_the_cap_is_accepted PASSED [ 95%]
tests/test_untrusted_input.py::test_one_byte_over_the_cap_is_rejected PASSED [ 95%]
tests/test_untrusted_input.py::test_non_utf8_bytes_are_rejected_with_the_offset PASSED [ 95%]
tests/test_untrusted_input.py::test_nul_byte_is_rejected PASSED          [ 95%]
tests/test_untrusted_input.py::test_escape_character_is_rejected PASSED  [ 95%]
tests/test_untrusted_input.py::test_ordinary_whitespace_is_allowed[\t] PASSED [ 95%]
tests/test_untrusted_input.py::test_ordinary_whitespace_is_allowed[\n] PASSED [ 95%]
tests/test_untrusted_input.py::test_ordinary_whitespace_is_allowed[\r\n] PASSED [ 95%]
tests/test_untrusted_input.py::test_high_unicode_is_not_treated_as_a_control_character PASSED [ 95%]
tests/test_untrusted_input.py::test_size_is_checked_before_the_file_is_read PASSED [ 95%]
tests/test_untrusted_input.py::test_caller_error_type_is_preserved PASSED [ 95%]
tests/test_untrusted_input.py::test_os_errors_are_normalized_with_their_cause PASSED [ 95%]
tests/test_untrusted_input.py::test_control_check_works_on_already_decoded_text PASSED [ 95%]
tests/test_untrusted_input.py::test_display_path_is_relative_for_a_file_under_the_cwd PASSED [ 95%]
tests/test_untrusted_input.py::test_rejection_message_does_not_leak_an_absolute_path PASSED [ 95%]
tests/test_untrusted_input.py::test_non_utf8_ledger_raises_instead_of_crashing PASSED [ 96%]
tests/test_untrusted_input.py::test_nul_laden_ledger_is_rejected PASSED  [ 96%]
tests/test_untrusted_input.py::test_oversized_ledger_is_rejected PASSED  [ 96%]
tests/test_untrusted_input.py::test_non_utf8_config_raises_instead_of_crashing PASSED [ 96%]
tests/test_untrusted_input.py::test_nul_laden_config_is_rejected PASSED  [ 96%]
tests/test_untrusted_input.py::test_oversized_config_is_rejected PASSED  [ 96%]
tests/test_untrusted_input.py::test_valid_config_at_exactly_the_cap_still_loads PASSED [ 96%]
tests/test_untrusted_input.py::test_poisoned_discovered_config_exits_two_without_a_traceback PASSED [ 96%]
tests/test_untrusted_input.py::test_poisoned_ledger_exits_two_without_a_traceback PASSED [ 96%]
tests/test_untrusted_input.py::test_nul_laden_ingest_response_exits_two PASSED [ 96%]
tests/test_untrusted_input.py::test_nul_laden_stdin_ingest_exits_two PASSED [ 96%]
tests/test_v1_2_false_positive_fixes.py::test_license_field_is_standard PASSED [ 96%]
tests/test_v1_2_false_positive_fixes.py::test_metadata_field_is_standard PASSED [ 96%]
tests/test_v1_2_false_positive_fixes.py::test_homepage_field_is_ecosystem_info PASSED [ 96%]
tests/test_v1_2_false_positive_fixes.py::test_repository_field_is_ecosystem_info PASSED [ 96%]
tests/test_v1_2_false_positive_fixes.py::test_unknown_field_still_warns PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_user_extension_field_is_silent PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_claude_api_name_warns_without_error PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_claude_api_name_validation_passes PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_canvas_design_pattern_warns_without_error PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_canvas_design_pattern_validation_passes PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_template_explicit_flag_skips_deployment_checks PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_template_placeholder_description_skips_deployment_checks PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_template_directory_skips_deployment_checks PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_template_detection_keeps_body_budget_rule PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_non_template_placeholder_word_documents_false_positive PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_claude_api_name_cli_exit_code_zero PASSED [ 97%]
tests/test_v1_2_false_positive_fixes.py::test_canvas_design_pattern_cli_exit_code_zero PASSED [ 97%]
tests/test_v1_architecture.py::test_core_module_surface_imports_cleanly PASSED [ 97%]
tests/test_v1_architecture.py::test_semantic_functions_are_callable PASSED [ 97%]
tests/test_v1_architecture.py::test_graph_extract_heuristic_is_callable PASSED [ 97%]
tests/test_v1_architecture.py::test_history_module_is_implemented PASSED [ 98%]
tests/test_v1_architecture.py::test_agent_base_interface_shape PASSED    [ 98%]
tests/test_v1_architecture.py::test_public_api_exports_unchanged PASSED  [ 98%]
tests/test_v1_architecture.py::test_validate_smoke_for_known_good_and_bad_fixtures PASSED [ 98%]
tests/test_v1_completion.py::test_format_md_outputs_markdown_report PASSED [ 98%]
tests/test_v1_completion.py::test_format_agent_outputs_agent_report PASSED [ 98%]
tests/test_v1_completion.py::test_agent_reason_emits_combined_packet PASSED [ 98%]
tests/test_v1_completion.py::test_semantic_enables_graph_analysis PASSED [ 98%]
tests/test_v1_completion.py::test_activation_hypotheses_json PASSED      [ 98%]
tests/test_v1_completion.py::test_tracemantle_toml_applies_defaults PASSED [ 98%]
tests/test_v1_completion.py::test_json_diagnostics_include_source_and_confidence PASSED [ 98%]
tests/test_version_coherence.py::test_pyproject_and_init_versions_match PASSED [ 98%]
tests/test_version_coherence.py::test_changelog_top_release_matches_init PASSED [ 98%]
tests/test_version_coherence.py::test_self_host_skill_version_matches PASSED [ 98%]
tests/test_version_coherence.py::test_only_one_self_host_skill_is_tracked PASSED [ 98%]
tests/test_yaml_anchors.py::test_anchor_and_alias_detected PASSED        [ 99%]
tests/test_yaml_anchors.py::test_anchor_only_detected PASSED             [ 99%]
tests/test_yaml_anchors.py::test_no_anchors_passes PASSED                [ 99%]
tests/test_yaml_anchors.py::test_no_frontmatter_passes PASSED            [ 99%]
tests/test_yaml_anchors.py::test_alias_in_body_not_flagged PASSED        [ 99%]
tests/test_yaml_anchors.py::test_ampersand_and_asterisk_in_quoted_value_not_flagged PASSED [ 99%]
tests/test_yaml_types.py::test_name_boolean_detected PASSED              [ 99%]
tests/test_yaml_types.py::test_name_integer_detected PASSED              [ 99%]
tests/test_yaml_types.py::test_name_float_detected PASSED                [ 99%]
tests/test_yaml_types.py::test_name_string_passes PASSED                 [ 99%]
tests/test_yaml_types.py::test_name_none_skipped PASSED                  [ 99%]
tests/test_yaml_types.py::test_name_quoted_true_passes PASSED            [ 99%]
tests/test_yaml_types.py::test_description_boolean_detected PASSED       [ 99%]
tests/test_yaml_types.py::test_description_integer_detected PASSED       [ 99%]
tests/test_yaml_types.py::test_description_string_passes PASSED          [ 99%]
tests/test_yaml_types.py::test_description_none_skipped PASSED           [100%]

================================ tests coverage ================================
_______________ coverage: platform linux, python 3.12.3-final-0 ________________

Name                                               Stmts   Miss  Cover   Missing
--------------------------------------------------------------------------------
src/tracemantle/__init__.py                            5      0   100%
src/tracemantle/__main__.py                            1      0   100%
src/tracemantle/adapters/__init__.py                  31      3    90%   60, 63, 66
src/tracemantle/adapters/neutral.py                   17     10    41%   14-24
src/tracemantle/adapters/promptfoo.py                 94     12    87%   33, 39, 42, 45, 48, 50, 57, 67, 71, 75, 95, 109
src/tracemantle/agents/__init__.py                    29      0   100%
src/tracemantle/agents/_ingest.py                     35      1    97%   134
src/tracemantle/agents/_response_text.py              12      0   100%
src/tracemantle/agents/base.py                        17      0   100%
src/tracemantle/agents/claude.py                       4      0   100%
src/tracemantle/agents/codex.py                        8      0   100%
src/tracemantle/agents/cursor.py                       8      0   100%
src/tracemantle/agents/graph_base.py                  17      0   100%
src/tracemantle/agents/graph_claude.py                 4      0   100%
src/tracemantle/agents/graph_codex.py                  8      0   100%
src/tracemantle/agents/graph_cursor.py                 8      0   100%
src/tracemantle/agents/graph_parser.py               107      8    93%   125, 138, 154, 176, 198, 243, 288, 295
src/tracemantle/agents/parser.py                      71      2    97%   144, 149
src/tracemantle/agents/schema.py                      35      0   100%
src/tracemantle/approvals.py                          36      8    78%   40, 42, 48, 54, 56, 58, 60-61
src/tracemantle/bundle.py                            128     23    82%   61, 64-65, 67, 81, 86, 91, 94, 100, 102-103, 108, 117-118, 123, 125, 127, 131, 133, 139, 141, 146, 148
src/tracemantle/cli.py                               154     36    77%   333, 335-345, 358-360, 363-366, 393-394, 405, 407, 412, 421-422, 425, 427, 429, 431, 443, 446, 456-457, 461-462, 466-467
src/tracemantle/commands.py                          392    151    61%   105, 110, 121-122, 125-127, 129-130, 136, 138, 140-142, 156-158, 160-165, 173, 180-181, 187-189, 200-204, 213-252, 256, 260, 264, 274-276, 286, 289-317, 328-329, 333, 337, 340-345, 347, 363, 377-382, 398, 421, 430, 433, 470, 484-485, 493-501, 506, 519-520, 543, 566-568, 572, 577-578, 601, 627-643, 651, 659-660, 672-673, 696-697, 712, 716-717, 731
src/tracemantle/comparison.py                        123      4    97%   68, 83, 165-166
src/tracemantle/config.py                             18      0   100%
src/tracemantle/config_loader.py                     165     11    93%   13-14, 103-104, 154, 159, 166, 170, 178, 230-231
src/tracemantle/core/__init__.py                      11      0   100%
src/tracemantle/core/activation.py                    76      3    96%   168-170
src/tracemantle/core/activation_render.py             20      0   100%
src/tracemantle/core/graph.py                        156      5    97%   234, 356, 368, 381, 407
src/tracemantle/core/graph_analyzers.py               88      3    97%   266, 271, 301
src/tracemantle/core/graph_model.py                   54      0   100%
src/tracemantle/core/graph_render.py                  42      0   100%
src/tracemantle/core/history.py                       89     19    79%   274-307
src/tracemantle/core/history_io.py                   113     18    84%   45, 50-52, 54, 57, 94, 122, 159, 169, 209-214, 251-254
src/tracemantle/core/semantic.py                      42      0   100%
src/tracemantle/core/symbolic.py                      19      5    74%   46-47, 72-73, 76
src/tracemantle/dependencies.py                       82      6    93%   50-51, 66, 71-73
src/tracemantle/display.py                             7      0   100%
src/tracemantle/evidence.py                           90      2    98%   35, 77
src/tracemantle/formatters.py                        145      5    97%   95-96, 204-206
src/tracemantle/history_store.py                      62      5    92%   40, 43, 45, 54, 72
src/tracemantle/io_limits.py                          61      3    95%   90-91, 186
src/tracemantle/markdown.py                          197     10    95%   120, 163, 171-173, 213-214, 217-219
src/tracemantle/modes.py                              46      0   100%
src/tracemantle/parser.py                            119      5    96%   95-98, 151
src/tracemantle/policy.py                            136     22    84%   15-16, 63, 67, 69, 71-72, 74, 82-83, 91, 96, 103, 105, 108, 111, 116, 119, 122, 124, 128, 131
src/tracemantle/product_commands.py                  149     42    72%   72-93, 96, 101, 116, 130, 132, 135, 137, 144, 155-165, 168-173
src/tracemantle/profile_freshness.py                  81      2    98%   26-27
src/tracemantle/promptfoo.py                           2      0   100%
src/tracemantle/result.py                             49      1    98%   24
src/tracemantle/rules/__init__.py                     56      5    91%   122, 159-162, 164
src/tracemantle/rules/compat.py                       93      4    96%   70, 86, 199, 213
src/tracemantle/rules/description.py                 178      8    96%   250-252, 267, 283, 334, 371, 404
src/tracemantle/rules/disclosure.py                   57      0   100%
src/tracemantle/rules/frontmatter.py                   6      0   100%
src/tracemantle/rules/frontmatter_common.py           33      4    88%   19, 22, 25, 41
src/tracemantle/rules/frontmatter_description.py      60      4    93%   59, 75, 93, 112
src/tracemantle/rules/frontmatter_fields.py           46      6    87%   55-60
src/tracemantle/rules/frontmatter_name.py             88      6    93%   52, 71, 74, 101, 149, 168
src/tracemantle/rules/references.py                   16      0   100%
src/tracemantle/rules/sizing.py                       21      0   100%
src/tracemantle/rules/template.py                      8      0   100%
src/tracemantle/signatures.py                         50      3    94%   52-53, 87
src/tracemantle/storage.py                            70      3    96%   26, 44, 91
src/tracemantle/template_detection.py                 15      1    93%   40
src/tracemantle/tokenizer.py                          28      6    79%   21, 29-32, 39
--------------------------------------------------------------------------------
TOTAL                                               4288    475    89%
Required test coverage of 80% reached. Total coverage: 88.92%
================= 1530 passed, 5 skipped in 184.02s (0:03:04) ==================
tracemantle --version
tracemantle 1.6.1
tracemantle skills/tracemantle/SKILL.md
✔ PASS  skills/tracemantle/SKILL.md
    line 4  · info              frontmatter.field.ecosystem  Field 'version' is ecosystem-common but not in the agentskills.io spec. Add it to tracemantle.toml under [frontmatter] extension_fields if intentional.
              version: ...
    line 5  · info              frontmatter.field.ecosystem  Field 'author' is ecosystem-common but not in the agentskills.io spec. Add it to tracemantle.toml under [frontmatter] extension_fields if intentional.
              author: ...
            · info              description.quality-score  Description quality score: 100/100.
            · info              compat.unverified  Behavior of field 'version' in codex, cursor is unverified (as of Codex: 2026-04-20; Cursor: 2026-04-20).
            · info              compat.unverified  Behavior of field 'author' in codex, cursor is unverified (as of Codex: 2026-04-20; Cursor: 2026-04-20).

Checked 1 file: 1 passed, 0 failed
tracemantle skills/tracemantle/SKILL.md --analyze-graph
Graph source: heuristic
✔ PASS  skills/tracemantle/SKILL.md
    line 4  · info              frontmatter.field.ecosystem  Field 'version' is ecosystem-common but not in the agentskills.io spec. Add it to tracemantle.toml under [frontmatter] extension_fields if intentional.
              version: ...
    line 5  · info              frontmatter.field.ecosystem  Field 'author' is ecosystem-common but not in the agentskills.io spec. Add it to tracemantle.toml under [frontmatter] extension_fields if intentional.
              author: ...
            · info              description.quality-score  Description quality score: 100/100.
            · info              compat.unverified  Behavior of field 'version' in codex, cursor is unverified (as of Codex: 2026-04-20; Cursor: 2026-04-20).
            · info              compat.unverified  Behavior of field 'author' in codex, cursor is unverified (as of Codex: 2026-04-20; Cursor: 2026-04-20).

Checked 1 file: 1 passed, 0 failed
OK: migration pre-commit rev matches v1.6.1
python3 -m build --no-isolation --outdir candidate-dist
* Getting build dependencies for sdist...
* Building sdist...
* Building wheel from sdist
* Getting build dependencies for wheel...
* Building wheel...
Successfully built tracemantle-1.6.1.tar.gz and tracemantle-1.6.1-py3-none-any.whl
python3 scripts/verify_artifacts.py candidate-dist
{
  "python": "3.12.3 (main, Aug 31 2026, 10:18:26) [GCC 13.3.0]",
  "checks": [
    {
      "artifact": "tracemantle-1.6.1-py3-none-any.whl",
      "sha256": "b23bc255c8f064e2508badef74a2a48330502d602a81a692856e9d9a96a49889",
      "version": "1.6.1",
      "clean_install": "passed",
      "setext_dependencies": "passed",
      "numeric_overflow": "passed",
      "legacy_migration": "not requested"
    },
    {
      "artifact": "tracemantle-1.6.1.tar.gz",
      "sha256": "60ccd999f4455831c0957c750e95eedf2b66fbac4055a9c9656445bb0b8eb9b8",
      "version": "1.6.1",
      "clean_install": "passed",
      "setext_dependencies": "passed",
      "numeric_overflow": "passed",
      "legacy_migration": "not requested"
    }
  ]
}
