@ngocsangairvds/vsaf 3.2.13 → 3.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/vsaf.js +13 -0
- package/package.json +1 -1
- package/src/config.js +167 -0
- package/src/global.js +34 -51
- package/src/utils.js +44 -1
- package/tools/vds-scripts/Makefile +9 -31
- package/tools/vds-scripts/docker/docker-compose.cli.yml +1 -117
- package/tools/vds-scripts/docker/docker-compose.services.yml +1 -40
- package/tools/vds-scripts/docker/infrastructure/init-schemas.sql +0 -34
- package/tools/vds-scripts/docker/infrastructure/pgbouncer/pgbouncer.ini +2 -6
- package/tools/vds-scripts/pyproject.toml +1 -33
- package/tools/vds-scripts/uv.lock +80 -1651
- package/tools/vds-scripts/vds_cli/pyproject.toml +3 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/cli.py +1 -127
- package/tools/vds-scripts/vds_cli/src/vds_cli/commands/lint_cli.py +1 -20
- package/tools/vds-scripts/vds_cli/src/vds_cli/router.py +0 -100
- package/tools/vds-scripts/vds_cli/tests/conftest.py +0 -2
- package/tools/vds-scripts/vds_cli/tests/unit/test_cli.py +0 -25
- package/tools/vds-scripts/vds_cli/tests/unit/test_lint_cli.py +2 -2
- package/tools/vds-scripts/vds_cli/tests/unit/test_router.py +0 -2
- package/tools/vds-scripts/CLOSURE.md +0 -340
- package/tools/vds-scripts/ECOSYSTEM-CHANGELOG.md +0 -52
- package/tools/vds-scripts/ECOSYSTEM-DOCS.md +0 -602
- package/tools/vds-scripts/ECOSYSTEM_ALIGNMENT.md +0 -133
- package/tools/vds-scripts/ENV-HYGIENE-OPS-NOTE.md +0 -65
- package/tools/vds-scripts/INVESTIGATION-cloud-401.md +0 -103
- package/tools/vds-scripts/MEM0_2.0_API_REFERENCE.md +0 -238
- package/tools/vds-scripts/PACKAGE_P125B_IMPLEMENTATION_SUMMARY.md +0 -131
- package/tools/vds-scripts/PHASE-MERGE-SUMMARY.md +0 -121
- package/tools/vds-scripts/PHASES-3-ARCHIVE.md +0 -59
- package/tools/vds-scripts/PROJECT_COMPLETION_SUMMARY.md +0 -45
- package/tools/vds-scripts/SEARCH-CRASH-REPRO.md +0 -51
- package/tools/vds-scripts/analyze_hexagonal.py +0 -217
- package/tools/vds-scripts/analyze_profiles.py +0 -60
- package/tools/vds-scripts/audit-checklist.xlsx +0 -0
- package/tools/vds-scripts/audit_orchestrator/.audit_approvals/approvals_index.json +0 -1
- package/tools/vds-scripts/audit_orchestrator/.env.example +0 -85
- package/tools/vds-scripts/audit_orchestrator/.github/workflows/audit.yml +0 -47
- package/tools/vds-scripts/audit_orchestrator/Dockerfile +0 -92
- package/tools/vds-scripts/audit_orchestrator/GOOGLE_SHEETS_IMPLEMENTATION_SUMMARY.md +0 -218
- package/tools/vds-scripts/audit_orchestrator/PHASE3_INTEGRATION_SUMMARY.md +0 -268
- package/tools/vds-scripts/audit_orchestrator/PHASE7-MERGE-SUMMARY.md +0 -174
- package/tools/vds-scripts/audit_orchestrator/README.md +0 -1573
- package/tools/vds-scripts/audit_orchestrator/TSK-168-IMPLEMENTATION-SUMMARY.md +0 -191
- package/tools/vds-scripts/audit_orchestrator/TSK-196-IMPLEMENTATION-SUMMARY.md +0 -201
- package/tools/vds-scripts/audit_orchestrator/alembic/env.py +0 -37
- package/tools/vds-scripts/audit_orchestrator/alembic/script.py.mako +0 -28
- package/tools/vds-scripts/audit_orchestrator/alembic/versions/0001_initial_audit_state_schema.py +0 -1260
- package/tools/vds-scripts/audit_orchestrator/alembic.ini +0 -68
- package/tools/vds-scripts/audit_orchestrator/config/category-mapping.json +0 -81
- package/tools/vds-scripts/audit_orchestrator/config/profile-timeouts.yaml +0 -17
- package/tools/vds-scripts/audit_orchestrator/create_sample.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/data/corpus_accuracy_report.json +0 -17
- package/tools/vds-scripts/audit_orchestrator/data/exemplar_quality_report.json +0 -1606
- package/tools/vds-scripts/audit_orchestrator/data/instruction_plan_fixtures.json +0 -163
- package/tools/vds-scripts/audit_orchestrator/data/requirement_exemplars.json +0 -3443
- package/tools/vds-scripts/audit_orchestrator/data/requirement_scope_fixtures.json +0 -172
- package/tools/vds-scripts/audit_orchestrator/debug_rg.py +0 -46
- package/tools/vds-scripts/audit_orchestrator/demo_code_pack.py +0 -127
- package/tools/vds-scripts/audit_orchestrator/docs/AGENT_SDK_SELECTION_SPEC.md +0 -720
- package/tools/vds-scripts/audit_orchestrator/docs/API.md +0 -804
- package/tools/vds-scripts/audit_orchestrator/docs/CONTENT_ANALYSIS_APPROACH.md +0 -1041
- package/tools/vds-scripts/audit_orchestrator/docs/CONTENT_SCORING_EVOLUTION_SPEC.md +0 -868
- package/tools/vds-scripts/audit_orchestrator/docs/DEPLOYMENT.md +0 -778
- package/tools/vds-scripts/audit_orchestrator/docs/LLM_AGENT_AUDIT_SPEC.md +0 -721
- package/tools/vds-scripts/audit_orchestrator/docs/LLM_CONTENT_ANALYSIS_SPEC.md +0 -1143
- package/tools/vds-scripts/audit_orchestrator/docs/LSP_SETUP_GUIDE.md +0 -221
- package/tools/vds-scripts/audit_orchestrator/docs/MULTI_REPO_AUDIT_SPEC.md +0 -951
- package/tools/vds-scripts/audit_orchestrator/docs/OLLAMA_EMBEDDINGS_SETUP.md +0 -119
- package/tools/vds-scripts/audit_orchestrator/docs/PHASE32_REAL_BENCHMARK_2026-02-08.md +0 -66
- package/tools/vds-scripts/audit_orchestrator/docs/PHASE_64_TO_92_HISTORICAL_SPEC.md +0 -1772
- package/tools/vds-scripts/audit_orchestrator/docs/TSK-193-flow-trace.md +0 -201
- package/tools/vds-scripts/audit_orchestrator/docs/TSK-193-verification.md +0 -124
- package/tools/vds-scripts/audit_orchestrator/docs/phase152-hierarchical-query-surface.md +0 -46
- package/tools/vds-scripts/audit_orchestrator/examples/bitbucket_metadata_example.json +0 -50
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/README.md +0 -68
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase117_phase118_shared_state.sql +0 -64
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase154_published_pages.sql +0 -28
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase157_dispatch_tables.sql +0 -94
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase157_events.sql +0 -91
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase157_scope_snapshots.sql +0 -24
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase157_status_view.sql +0 -22
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase169_dispatch_observability.sql +0 -55
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/state_repair_hardening.sql +0 -24
- package/tools/vds-scripts/audit_orchestrator/pyproject.toml +0 -211
- package/tools/vds-scripts/audit_orchestrator/pyrightconfig.json +0 -51
- package/tools/vds-scripts/audit_orchestrator/pytest.ini +0 -37
- package/tools/vds-scripts/audit_orchestrator/reproduce_scanner.py +0 -40
- package/tools/vds-scripts/audit_orchestrator/scripts/README.md +0 -116
- package/tools/vds-scripts/audit_orchestrator/scripts/benchmark_crawl_modes.py +0 -455
- package/tools/vds-scripts/audit_orchestrator/scripts/benchmark_dspy.py +0 -513
- package/tools/vds-scripts/audit_orchestrator/scripts/benchmark_nlp_accuracy.py +0 -138
- package/tools/vds-scripts/audit_orchestrator/scripts/benchmark_retrieval_modes.py +0 -176
- package/tools/vds-scripts/audit_orchestrator/scripts/benchmark_upload_update_mode.py +0 -167
- package/tools/vds-scripts/audit_orchestrator/scripts/build_check.py +0 -76
- package/tools/vds-scripts/audit_orchestrator/scripts/check_live_progress.py +0 -61
- package/tools/vds-scripts/audit_orchestrator/scripts/cli_integration_test.py +0 -400
- package/tools/vds-scripts/audit_orchestrator/scripts/index_workspace.py +0 -178
- package/tools/vds-scripts/audit_orchestrator/scripts/inspect_route_conformance.py +0 -196
- package/tools/vds-scripts/audit_orchestrator/scripts/monitor_postgres.py +0 -145
- package/tools/vds-scripts/audit_orchestrator/scripts/optimize_audit.py +0 -462
- package/tools/vds-scripts/audit_orchestrator/scripts/verify.py +0 -673
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase111_requirement_analysis.py +0 -375
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase117_cross_repo_evidence.py +0 -77
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase121_short_circuit.py +0 -680
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase122_instruction_handling.py +0 -478
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase125_skill_integration.py +0 -832
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase_36.py +0 -394
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase_37.py +0 -58
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/__init__.py +0 -17
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/__init__.py +0 -29
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/_langchain_warnings.py +0 -17
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/agentic_investigator.py +0 -4130
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/approval.py +0 -490
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/audit_loop_hooks.py +0 -107
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/audit_state.py +0 -50
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/base.py +0 -4035
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/code_agent.py +0 -667
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/code_analysis_helpers.py +0 -236
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/code_analysis_prompts.py +0 -146
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/docs_agent.py +0 -1234
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/langgraph_workflow.py +0 -2002
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/pydantic_base.py +0 -1227
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/requirement_analysis_agent.py +0 -593
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/security_agent.py +0 -1829
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/security_scanner.py +0 -686
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/skill_tools.py +0 -204
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/synthesis_agent.py +0 -1463
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/tool_efficiency_guard.py +0 -609
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/tool_registry.py +0 -3822
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/__init__.py +0 -52
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/evidence_corpus.py +0 -385
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/filesystem.py +0 -1134
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/lsp.py +0 -458
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/mcp_toolset.py +0 -491
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/skills_toolset.py +0 -997
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/vector_evidence.py +0 -842
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/usage_tracker.py +0 -682
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/visualization.py +0 -303
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/analyze_cmds.py +0 -892
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checklist_query/__init__.py +0 -15
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checklist_query/service.py +0 -171
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/__init__.py +0 -20
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/base.py +0 -60
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/bitbucket/__init__.py +0 -6
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/bitbucket/checks.py +0 -257
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/confluence/__init__.py +0 -10
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/confluence/checks.py +0 -78
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/git/__init__.py +0 -6
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/git/file_checks.py +0 -133
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/llm_checks/__init__.py +0 -17
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/llm_checks/api_docs_check.py +0 -80
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/llm_checks/readme_check.py +0 -76
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/llm_checks/security_docs_check.py +0 -78
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/registry.py +0 -402
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/sonarqube/__init__.py +0 -10
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/sonarqube/checks.py +0 -276
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/cli.py +0 -12
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/cli_common.py +0 -128
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/cli_impl.py +0 -9826
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/clients/bitbucket_cli_client.py +0 -187
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/clients/confluence_cli_client.py +0 -977
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/clients/sonarqube_cli_client.py +0 -28
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/__init__.py +0 -21
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/base.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/bitbucket_downloader.py +0 -644
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/bitbucket_metadata.py +0 -133
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/checklist_parser.py +0 -180
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/completeness/__init__.py +0 -31
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/completeness/bitbucket_probe.py +0 -443
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/completeness/confluence_probe.py +0 -365
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/completeness/freshness_evaluator.py +0 -330
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/completeness/material_completeness_service.py +0 -1079
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/confluence_collector.py +0 -259
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/diagram_extractor.py +0 -280
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/enrichment_extractor.py +0 -200
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/evidence_cache.py +0 -35
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/git_collector.py +0 -148
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/graphify_collector.py +0 -171
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/image_extractor.py +0 -359
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/linked_page_tracker.py +0 -120
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/markdown_converter.py +0 -344
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/material_cache.py +0 -1252
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/material_downloader.py +0 -1165
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/orchestrator.py +0 -168
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/registry_parser.py +0 -3063
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/requirements.py +0 -70
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/runner.py +0 -119
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/sonarqube_collector.py +0 -113
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config.py +0 -1943
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/__init__.py +0 -23
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/discovery.py +0 -90
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/environment_resolver.py +0 -56
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/evidence.py +0 -78
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/models.py +0 -73
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/precedence.py +0 -10
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/redaction.py +0 -20
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/confluence_connectivity.py +0 -140
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/corpus_cmds.py +0 -278
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/db/__init__.py +0 -7
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/db/alembic_filters.py +0 -57
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/docs/__init__.py +0 -29
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/docs/diataxis_validator.py +0 -687
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/doctor_cmds.py +0 -3295
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/dspy_modules/__init__.py +0 -5
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/dspy_modules/evaluation.py +0 -301
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/dspy_modules/modules.py +0 -172
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/dspy_modules/runtime.py +0 -836
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/dspy_modules/signatures.py +0 -406
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/__init__.py +0 -192
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/ad_hoc_analyzer.py +0 -399
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/aggregator.py +0 -220
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/auditor.py +0 -504
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/batch_evidence_cache.py +0 -111
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/batch_processor.py +0 -4776
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/calibration.py +0 -217
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/checklist_generator.py +0 -1201
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/checklist_projection.py +0 -192
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/checklist_scoping.py +0 -221
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/checkpoint.py +0 -159
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/cl003_shared_lib_guard.py +0 -194
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/companion_context_service.py +0 -445
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/confluence_checklist_contract.py +0 -7425
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/cross_check_rules.py +0 -213
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/deterministic_evaluator.py +0 -237
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/drift_detector.py +0 -157
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/dspy_requirement_classifier.py +0 -640
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/evidence_assembler.py +0 -407
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/evidence_collector.py +0 -119
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/evidence_diversity.py +0 -101
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/gap_analyzer.py +0 -549
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/graduated.py +0 -185
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/grounding_validator.py +0 -287
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/instruction_analyzer.py +0 -882
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/instruction_compliance.py +0 -172
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/llm_row_evaluator.py +0 -9270
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/loader.py +0 -1070
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/manual_check_config.py +0 -136
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/mapping.py +0 -269
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/multi_judge.py +0 -65
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/phase120_checklist_update.py +0 -416
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/profile_scorer.py +0 -427
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/project_evidence_context.py +0 -449
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/project_knowledge_query_service.py +0 -155
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/project_knowledge_store.py +0 -383
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/project_topology.py +0 -1920
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/provider_failure_classifier.py +0 -778
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/readiness_cli_helpers.py +0 -341
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/readiness_extractor.py +0 -303
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/readiness_synthesizer.py +0 -730
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/regression_guard.py +0 -138
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/repo_type_classifier.py +0 -297
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/requirement_analysis.py +0 -1433
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/requirement_classification.py +0 -1725
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/result_merger.py +0 -814
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/route_matrix.py +0 -267
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/row_evaluator.py +0 -9437
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/row_evaluator_runtime.py +0 -1270
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/row_evaluator_types.py +0 -2102
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/rubric.py +0 -592
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/scorer.py +0 -1239
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/section_packs.py +0 -645
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/skill_recommendation.py +0 -1183
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/stability_harness.py +0 -207
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/target_selector.py +0 -841
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/telemetry.py +0 -347
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/template_analyzer.py +0 -469
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/token_tracker.py +0 -111
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/tool_first_planner.py +0 -7905
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/topology_query_service.py +0 -80
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/validator.py +0 -449
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/weight_policy.py +0 -464
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/errors.py +0 -430
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/extract_cmds.py +0 -4887
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/identity.py +0 -146
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/incremental/__init__.py +0 -52
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/incremental/baseline.py +0 -378
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/incremental/change_analyzer.py +0 -407
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/incremental/delta_report.py +0 -189
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/incremental/diff_detector.py +0 -301
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/integrations/__init__.py +0 -3
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/__init__.py +0 -50
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/audit_schemas.py +0 -459
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/codex_oauth.py +0 -340
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/cost_tracker.py +0 -288
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/engine.py +0 -751
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/evaluator.py +0 -245
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/__init__.py +0 -32
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/api_docs_evaluation.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/gap_analysis.py +0 -31
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/instruction_templates.py +0 -634
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/readme_evaluation.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/row_evaluation.py +0 -247
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/security_docs_evaluation.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/template_analysis.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/provider.py +0 -626
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/logging_config.py +0 -577
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/mappings/__init__.py +0 -58
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/mappings/default_checklist_mapping.json +0 -18
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/mappings/vietnamese_checklist_mapping.json +0 -38
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/misc_cmds.py +0 -4689
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/__init__.py +0 -153
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/calibration.py +0 -98
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/checklist.py +0 -921
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/completeness.py +0 -309
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/enrichment.py +0 -58
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/enums.py +0 -97
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/evidence.py +0 -351
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/findings.py +0 -381
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/gaps.py +0 -299
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/graph.py +0 -42
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/multi_judge.py +0 -50
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/readiness.py +0 -309
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/registry.py +0 -386
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/reporting.py +0 -32
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/task.py +0 -549
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/template.py +0 -477
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/observability/__init__.py +0 -31
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/observability/metrics.py +0 -404
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/parse_cmds.py +0 -608
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/pdf_cmds.py +0 -208
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/performance_gates.py +0 -224
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/phase151_projection.py +0 -84
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/profiles/__init__.py +0 -65
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/profiles/detection.py +0 -842
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/profiles/models.py +0 -474
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/__init__.py +0 -1
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/_confluence_macros.py +0 -145
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/_field_sanitizer.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/_table_builder.py +0 -63
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/_vietnamese_templates.py +0 -103
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/bitbucket_link_resolver.py +0 -34
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/checklist_renderer.py +0 -483
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/confluence_publisher.py +0 -3048
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/hierarchy_publisher.py +0 -213
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/live_data_injector.py +0 -152
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/macro_builder.py +0 -101
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/markdown_converter.py +0 -154
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/priority_renderer.py +0 -133
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/project_aggregate_renderer.py +0 -423
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/readiness_renderer.py +0 -186
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/system_doc_hierarchy_renderer.py +0 -382
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/system_doc_renderer.py +0 -683
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/report_cmds.py +0 -788
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/__init__.py +0 -13
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/aggregation_report.py +0 -86
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/checklist_generator.py +0 -425
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/excel_generator.py +0 -599
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/gap_report.py +0 -131
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/json_generator.py +0 -188
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/markdown_generator.py +0 -595
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/__init__.py +0 -154
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/collector.py +0 -61
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/department_builder.py +0 -77
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/errors.py +0 -9
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/md_renderer.py +0 -386
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/pdf_models.py +0 -95
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/pdf_writer.py +0 -27
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/repo_project_builders.py +0 -274
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/readiness_report.py +0 -447
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/reporting.py +0 -94
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/sarif_generator.py +0 -519
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/runtime_profiles.py +0 -98
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/seed/__init__.py +0 -29
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/seed/seed_loader.py +0 -561
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/skills/__init__.py +0 -5
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/skills/skill_routing.py +0 -312
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/base.py +0 -110
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/bitbucket.py +0 -129
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/git_url.py +0 -60
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/github.py +0 -75
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/local.py +0 -58
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/spec_sync_validator.py +0 -15
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/state/__init__.py +0 -6285
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/state/readiness_helpers.py +0 -74
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/state/skill_readiness.py +0 -487
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/state/store.py +0 -12927
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/state_cmds.py +0 -1868
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sync/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sync/repo_sync.py +0 -409
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sync_cmds.py +0 -1247
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/utils/__init__.py +0 -3
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/utils/debug_bundle.py +0 -214
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/validators/checklist_validator.py +0 -342
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflow_cmds.py +0 -19147
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/__init__.py +0 -9
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/_test_audit_daily_batch.py +0 -192
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/audit_daily_batch.py +0 -308
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/audit_deep_monthly.py +0 -193
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/audit_drift_scan.py +0 -178
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/audit_security_daily.py +0 -183
- package/tools/vds-scripts/audit_orchestrator/templates/sample_audit_template.xlsx +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/_helpers.py +0 -32
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/completeness/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/completeness/test_bitbucket_probe.py +0 -403
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/completeness/test_confluence_probe.py +0 -423
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_bitbucket_downloader.py +0 -289
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_image_extractor.py +0 -260
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_markdown_converter.py +0 -57
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_material_cache.py +0 -197
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_material_downloader.py +0 -550
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_registry_parser.py +0 -3514
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_registry_parser_department_entry.py +0 -214
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_registry_parser_flow.py +0 -200
- package/tools/vds-scripts/audit_orchestrator/tests/conftest.py +0 -988
- package/tools/vds-scripts/audit_orchestrator/tests/engine/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/engine/test_calibration.py +0 -48
- package/tools/vds-scripts/audit_orchestrator/tests/engine/test_confluence_checklist_phase22_helpers.py +0 -6065
- package/tools/vds-scripts/audit_orchestrator/tests/engine/test_multi_judge.py +0 -62
- package/tools/vds-scripts/audit_orchestrator/tests/engine/test_stability_harness.py +0 -61
- package/tools/vds-scripts/audit_orchestrator/tests/engine/test_structured_metadata.py +0 -419
- package/tools/vds-scripts/audit_orchestrator/tests/factories/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/factories/models.py +0 -534
- package/tools/vds-scripts/audit_orchestrator/tests/factories/templates.py +0 -241
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/diagrams/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/diagrams/compressed.drawio +0 -2
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/diagrams/mockup.bmpr +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/diagrams/simple.drawio +0 -26
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/bitbucket/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/bitbucket/branch_permissions_cli.json +0 -26
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/bitbucket/branch_permissions_direct.json +0 -24
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/bitbucket/repo_conditions_cli.json +0 -14
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/bitbucket/repo_conditions_direct.json +0 -12
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/confluence/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/confluence/page_cli.json +0 -7
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/confluence/page_direct.json +0 -7
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/confluence/search_cli.json +0 -11
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/confluence/search_direct.json +0 -7
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/sonarqube/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/sonarqube/quality_gate_cli.json +0 -12
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/sonarqube/quality_gate_direct.json +0 -12
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/requirement_strategy_phase115.json +0 -118
- package/tools/vds-scripts/audit_orchestrator/tests/integration/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/conftest.py +0 -107
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/expected_outcomes.md +0 -50
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/auth.py +0 -27
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/config.py +0 -16
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/db.py +0 -24
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/main.py +0 -18
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/src/__init__.py +0 -1
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/src/utils.py +0 -22
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_checklist_template.json +0 -110
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/code_evidence_pack.json +0 -40
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/manifest.json +0 -49
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/brd.md +0 -19
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/design.md +0 -32
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/security.md +0 -23
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/srs.md +0 -25
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/test.md +0 -30
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_checkpoint_merge.py +0 -1371
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_decoupling_route_p149.py +0 -176
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_gap_analyzer_batch_p149.py +0 -151
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_hybrid_search.py +0 -799
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_mcp_integration.py +0 -741
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_merge_ranking_p149.py +0 -98
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_modality_mismatch_p149.py +0 -171
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_phase117_118_storage.py +0 -350
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_phase121_short_circuit.py +0 -732
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_phase18_workflow.py +0 -223
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_phase48_e2e_verification.py +0 -763
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_phase81_doc_anchor_regression.py +0 -252
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_provider_failure_finding_p149.py +0 -339
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_readiness_e2e.py +0 -430
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_refined_workflow.py +0 -1180
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/snapshots/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/snapshots/department_renderer.md +0 -24
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/snapshots/project_renderer.md +0 -8
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/snapshots/repo_renderer.md +0 -10
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_department_pdf.py +0 -112
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_e2e_pdf.py +0 -135
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_idempotency.py +0 -45
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_md_renderer.py +0 -46
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_pdf_cmds.py +0 -97
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_pdf_snapshot.py +0 -77
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_pdf_writer.py +0 -65
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_project_builder.py +0 -199
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_public_api.py +0 -135
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_repo_builder.py +0 -246
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_workflow_pdf_flags.py +0 -36
- package/tools/vds-scripts/audit_orchestrator/tests/property/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/property/test_properties.py +0 -807
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_agent_error_compat.py +0 -38
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_agentic_skill_policy_skip.py +0 -234
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_base_event_stream_logging.py +0 -785
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_base_timeout_policy.py +0 -277
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_base_trace_payload_sanitization.py +0 -92
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_code_agent.py +0 -2311
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_code_agent_re_exports.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_code_analysis_helpers.py +0 -94
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_create_audit_agent_reasoning_effort.py +0 -69
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_docs_agent.py +0 -2044
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_langgraph_workflow_efficiency_metrics.py +0 -71
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_output_validators.py +0 -317
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_phase41_toolsets.py +0 -6427
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_pydantic_ai_models.py +0 -1219
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_pydantic_base_url_resolution.py +0 -84
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_security_agent.py +0 -2069
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_skill_manager_focus.py +0 -439
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_synthesis_agent.py +0 -1195
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_tool_efficiency_guard_fr120.py +0 -683
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_toolsets.py +0 -716
- package/tools/vds-scripts/audit_orchestrator/tests/test_aggregator_p149.py +0 -171
- package/tools/vds-scripts/audit_orchestrator/tests/test_alembic_migrations.py +0 -287
- package/tools/vds-scripts/audit_orchestrator/tests/test_anchor_allowlist_p149.py +0 -273
- package/tools/vds-scripts/audit_orchestrator/tests/test_audit_otel.py +0 -283
- package/tools/vds-scripts/audit_orchestrator/tests/test_checklist_models.py +0 -583
- package/tools/vds-scripts/audit_orchestrator/tests/test_checks/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_checks/test_base_check.py +0 -211
- package/tools/vds-scripts/audit_orchestrator/tests/test_checks/test_llm_checks.py +0 -126
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_analyze_command.py +0 -400
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_archive_stale_page_cli.py +0 -217
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_bitbucket_metadata_cli.py +0 -354
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_cli_impl_profile_availability.py +0 -114
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_codex_profile.py +0 -174
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_compare_backends_cli.py +0 -449
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_confluence_parent_auto_resolve.py +0 -451
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_corpus_purge_cli.py +0 -290
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_credentials_preflight.py +0 -106
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_debug_bundle.py +0 -37
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_deprecation_phase157.py +0 -484
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_dispatch_concurrency_diagnostics.py +0 -758
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_check_confluence_cli.py +0 -320
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_codex.py +0 -187
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_corpus_status_cli.py +0 -236
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_correlation_cli.py +0 -128
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_crawl_status_cli.py +0 -192
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_credentials_cli.py +0 -86
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_dispatch_status_cli.py +0 -421
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_heartbeat_phase169.py +0 -173
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_hierarchy_status_cli.py +0 -199
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_locks_cli.py +0 -134
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_logs_follow_cli.py +0 -305
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_migration.py +0 -333
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_profile_availability_cli.py +0 -151
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_skills_policy_cli.py +0 -153
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_evidence_quality_cli.py +0 -307
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_export_debug_bundle_phase36.py +0 -60
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_export_git_manifest_cli.py +0 -172
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_file_removal_phase157e.py +0 -770
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_grounding_classifier.py +0 -226
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_logging.py +0 -49
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_materials_cli.py +0 -9127
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_metadata_completeness_phase92.py +0 -364
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_parent_dispatch_finalization_phase168f.py +0 -111
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_parse_cli.py +0 -590
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_phase117_118_feature_flags.py +0 -219
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_phase164_control_plane.py +0 -718
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_phase165_runner_scripts.py +0 -230
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_preparation_classifications.py +0 -146
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_prepare_cli.py +0 -398
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_publication_quality_gate.py +0 -126
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_publish_system_doc_cli.py +0 -158
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_query_checklist_cli.py +0 -219
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_readiness_cli.py +0 -673
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_readiness_cli_integration.py +0 -689
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_removed_flags_phase92.py +0 -36
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_report_cmds.py +0 -1317
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_run_history_index.py +0 -57
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_run_management.py +0 -1194
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_runtime_profiles_cli.py +0 -1658
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_smart_run_selection.py +0 -1562
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_state_cli.py +0 -2467
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_state_migration.py +0 -339
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_sync_repos_debug_artifacts.py +0 -1109
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_upload_results_cli.py +0 -809
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_validate_checklist.py +0 -178
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_validate_checklist_cli.py +0 -110
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_validate_spec_sync_cli.py +0 -519
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_default_parameters_baseline.py +0 -101
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_options.py +0 -7896
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_project_db_modes.py +0 -6516
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_project_project_scope.py +0 -831
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_project_target.py +0 -611
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_projects_phase131_lifecycle.py +0 -2488
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_projects_phase131_scaffolding.py +0 -96
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_row_key_guard.py +0 -78
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_summary_artifacts.py +0 -1872
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli_paths_phase2.py +0 -45
- package/tools/vds-scripts/audit_orchestrator/tests/test_clients/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_clients/test_bitbucket_cli_client.py +0 -124
- package/tools/vds-scripts/audit_orchestrator/tests/test_clients/test_cli_parity.py +0 -110
- package/tools/vds-scripts/audit_orchestrator/tests/test_clients/test_confluence_cli_client.py +0 -1149
- package/tools/vds-scripts/audit_orchestrator/tests/test_clients/test_sonarqube_cli_client.py +0 -19
- package/tools/vds-scripts/audit_orchestrator/tests/test_collectors/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_collectors/test_linked_page_tracker.py +0 -118
- package/tools/vds-scripts/audit_orchestrator/tests/test_companion_context_service.py +0 -230
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/conftest.py +0 -11
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_compile_artifact.py +0 -465
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_cross_provider_critique.py +0 -120
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_cross_provider_critique_e2e.py +0 -75
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_evaluation.py +0 -515
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_runtime_loader.py +0 -537
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_signatures_normalization.py +0 -172
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_auditor_applicability.py +0 -68
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_checklist_generator.py +0 -1252
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_checklist_projection.py +0 -54
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_confluence_checklist_projection_consistency.py +0 -1696
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_critique_merger_matrix.py +0 -120
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_cross_check_rules.py +0 -459
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_cross_provider_critique.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_doc_loader.py +0 -73
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_drift_detector.py +0 -34
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_evidence_collectors.py +0 -93
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_lease_timeout.py +0 -114
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_loader.py +0 -350
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_loader_parity.py +0 -179
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_low_confidence_reeval.py +0 -691
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_phase145a_completion.py +0 -209
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_phase31_row_consistency_retry_benchmark.py +0 -150
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_profile_detector.py +0 -286
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_regression_guard.py +0 -53
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_result_merger.py +0 -619
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_row_evaluator.py +0 -15783
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_row_failover.py +0 -215
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_scorer.py +0 -597
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_skill_breakdown_telemetry_fr137.py +0 -421
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_targeted_auto_merge.py +0 -229
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_timeout_failover.py +0 -488
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_timeout_telemetry.py +0 -73
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_validator.py +0 -419
- package/tools/vds-scripts/audit_orchestrator/tests/test_incremental/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_incremental/test_diff_detector.py +0 -111
- package/tools/vds-scripts/audit_orchestrator/tests/test_infra_persistence.py +0 -291
- package/tools/vds-scripts/audit_orchestrator/tests/test_integration/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_integration/test_phase3_integration.py +0 -516
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_cache.py +0 -670
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_codex_model_builder.py +0 -281
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_codex_oauth.py +0 -330
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_codex_streaming.py +0 -433
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_cost_tracker.py +0 -27
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_engine.py +0 -876
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_evaluator.py +0 -212
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_instruction_templates.py +0 -639
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_prompt_metadata.py +0 -97
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_prompts.py +0 -660
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_provider.py +0 -330
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_provider_contract_sync.py +0 -18
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_reasoning_effort_validation.py +0 -565
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_schemas.py +0 -827
- package/tools/vds-scripts/audit_orchestrator/tests/test_logging_config.py +0 -297
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/test_enums.py +0 -185
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/test_findings.py +0 -1159
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/test_project_profile.py +0 -307
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/test_registry.py +0 -532
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/test_template.py +0 -708
- package/tools/vds-scripts/audit_orchestrator/tests/test_observability/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_observability/test_metrics.py +0 -60
- package/tools/vds-scripts/audit_orchestrator/tests/test_paths_config_phase2.py +0 -21
- package/tools/vds-scripts/audit_orchestrator/tests/test_performance/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_performance/test_fr79_performance_guardrails.py +0 -199
- package/tools/vds-scripts/audit_orchestrator/tests/test_phase156_hardening.py +0 -498
- package/tools/vds-scripts/audit_orchestrator/tests/test_phase93_regression_guards.py +0 -123
- package/tools/vds-scripts/audit_orchestrator/tests/test_pipeline_integration.py +0 -517
- package/tools/vds-scripts/audit_orchestrator/tests/test_profiles/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_profiles/test_detection.py +0 -146
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_bitbucket_link_resolver.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_checklist_renderer.py +0 -84
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_checklist_renderer_projection.py +0 -97
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_confluence_macros.py +0 -58
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_confluence_publisher.py +0 -2171
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_evidence_links.py +0 -129
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_field_sanitizer.py +0 -108
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_hierarchy_publisher.py +0 -134
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_incremental_plan_parser.py +0 -62
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_live_data_injector.py +0 -48
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_macro_builder.py +0 -22
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_p161_confluence_optimization.py +0 -168
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_priority_renderer.py +0 -96
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_project_aggregate_renderer.py +0 -364
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_storage_validation.py +0 -273
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_summary_refactor.py +0 -118
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_system_doc_hierarchy.py +0 -50
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_table_builder.py +0 -23
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_vietnamese_templates.py +0 -37
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_wiring_integration.py +0 -290
- package/tools/vds-scripts/audit_orchestrator/tests/test_reports/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_reports/test_aggregation_report.py +0 -181
- package/tools/vds-scripts/audit_orchestrator/tests/test_reports/test_checklist_generator.py +0 -258
- package/tools/vds-scripts/audit_orchestrator/tests/test_reports/test_gap_report.py +0 -73
- package/tools/vds-scripts/audit_orchestrator/tests/test_reports/test_json_generator.py +0 -317
- package/tools/vds-scripts/audit_orchestrator/tests/test_result_merger_p149.py +0 -347
- package/tools/vds-scripts/audit_orchestrator/tests/test_route_mode_p149.py +0 -178
- package/tools/vds-scripts/audit_orchestrator/tests/test_rubric_parser.py +0 -179
- package/tools/vds-scripts/audit_orchestrator/tests/test_scorer.py +0 -110
- package/tools/vds-scripts/audit_orchestrator/tests/test_state/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_state/test_sparse_coverage.py +0 -117
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow/test_langgraph_workflow.py +0 -2072
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow/test_p161_runtime_hardening.py +0 -341
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow_cmds_p149.py +0 -112
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow_cmds_p172.py +0 -126
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow_guidance_p150.py +0 -95
- package/tools/vds-scripts/audit_orchestrator/tests/unit/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_agentic_investigator_phase115.py +0 -42
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_requirement_analysis_agent.py +0 -412
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_security_agent_updates.py +0 -131
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_security_scanner.py +0 -397
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_skill_executor.py +0 -316
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_skill_fallback.py +0 -299
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_skill_policy.py +0 -520
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_skill_telemetry.py +0 -306
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_synthesis_fixes.py +0 -761
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_argument_robustness.py +0 -272
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_registry.py +0 -2548
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_registry_ast_grep.py +0 -87
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_registry_phase123_scoping.py +0 -353
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_registry_phase94_ff.py +0 -445
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_registry_vector_search_phase115.py +0 -35
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_utils.py +0 -1007
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_vector_evidence_toolset.py +0 -622
- package/tools/vds-scripts/audit_orchestrator/tests/unit/cli/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/cli/test_workflow_cli.py +0 -123
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/test_cache_guard.py +0 -479
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/test_checklist_parser_phase120.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/test_diagram_extractor.py +0 -467
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/test_enrichment_extractor.py +0 -59
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/test_graphify_collector.py +0 -158
- package/tools/vds-scripts/audit_orchestrator/tests/unit/completeness/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/completeness/test_completeness.py +0 -563
- package/tools/vds-scripts/audit_orchestrator/tests/unit/completeness/test_freshness_evaluator.py +0 -493
- package/tools/vds-scripts/audit_orchestrator/tests/unit/completeness/test_material_cache_metrics.py +0 -365
- package/tools/vds-scripts/audit_orchestrator/tests/unit/completeness/test_material_completeness_service.py +0 -2736
- package/tools/vds-scripts/audit_orchestrator/tests/unit/config_resolution/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/config_resolution/test_discovery.py +0 -47
- package/tools/vds-scripts/audit_orchestrator/tests/unit/config_resolution/test_redaction.py +0 -15
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_ad_hoc_analyzer.py +0 -576
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_agent_loop.py +0 -1896
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_anchor_filter_cl003.py +0 -181
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_batch_evidence_cache.py +0 -155
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_batch_processor.py +0 -3608
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_checklist_contract.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_checklist_scoping.py +0 -371
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_config_companion_phase123.py +0 -142
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_config_evidence_phase123.py +0 -249
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_confluence_checklist_contract_export_parity.py +0 -813
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_cross_repo_config_phase122.py +0 -613
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_dspy_requirement_classifier.py +0 -517
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_evidence_diversity.py +0 -144
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_evidence_truncation.py +0 -108
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_grounding_validator.py +0 -127
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_guidance_injection_phase120.py +0 -105
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_instruction_analysis_phase122.py +0 -761
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_instruction_pre_filter_phase167.py +0 -334
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_llm_row_evaluator_retries.py +0 -3684
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_loader_phase123.py +0 -345
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_manual_check_gating_phase122.py +0 -474
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_parallel_eval.py +0 -263
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_phase122_verifier_phase122.py +0 -169
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_phase166_route_failover.py +0 -437
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_post_eval_cl003_shared_lib.py +0 -267
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_postproc_streaming.py +0 -194
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_pre_eval_gating_phase122.py +0 -362
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_prepare_topology_coverage.py +0 -247
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_private_dns_sanitization_phase104.py +0 -397
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_project_evidence_context.py +0 -450
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_project_knowledge_store.py +0 -487
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_project_topology.py +0 -1142
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_provider_failure_classifier.py +0 -195
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_readiness_extractor.py +0 -496
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_readiness_synthesizer.py +0 -653
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_repo_type_classifier.py +0 -303
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_analysis.py +0 -508
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_analysis_execution_scope.py +0 -239
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_analysis_phase114.py +0 -919
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_analysis_phase115.py +0 -97
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_analysis_shared_lib.py +0 -340
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_classification_drift.py +0 -729
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_classification_nlp.py +0 -670
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_scope_phase122.py +0 -615
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_route_matrix.py +0 -258
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_route_override.py +0 -141
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_routing_precision.py +0 -650
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_row_evaluator_dual_evidence.py +0 -2987
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_row_evaluator_instruction_runtime_phase122.py +0 -365
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_row_evaluator_runtime.py +0 -830
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_runtime_hardening_phase122.py +0 -225
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_scoped_na_skip.py +0 -107
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_scoring_enhancements.py +0 -404
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_shared_library_retrieval_phase123.py +0 -441
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_shared_library_routing_phase123.py +0 -279
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_shared_resource_indexing_phase122.py +0 -188
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_skill_recommendation.py +0 -225
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_skill_routing_cl003_shared_lib.py +0 -338
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_skills_toolset.py +0 -319
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_stability_metric.py +0 -60
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_target_selector.py +0 -958
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_token_tracker.py +0 -121
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_token_wiring.py +0 -119
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_tool_first_planner.py +0 -7103
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_topology_knowledge_persistence.py +0 -332
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_topology_query_service.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_unverified_ref_retry.py +0 -909
- package/tools/vds-scripts/audit_orchestrator/tests/unit/models/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/models/test_evidence.py +0 -515
- package/tools/vds-scripts/audit_orchestrator/tests/unit/models/test_gaps.py +0 -422
- package/tools/vds-scripts/audit_orchestrator/tests/unit/models/test_readiness.py +0 -428
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_confluence_hierarchy.py +0 -227
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_project_title_generation.py +0 -335
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_publisher_registry_helpers.py +0 -290
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_publisher_registry_integration.py +0 -557
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_readiness_renderer.py +0 -381
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_repo_title_consistency.py +0 -266
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_upload_hierarchy_integration.py +0 -470
- package/tools/vds-scripts/audit_orchestrator/tests/unit/scripts/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/scripts/test_benchmark_dspy.py +0 -177
- package/tools/vds-scripts/audit_orchestrator/tests/unit/scripts/test_benchmark_nlp_accuracy.py +0 -72
- package/tools/vds-scripts/audit_orchestrator/tests/unit/scripts/test_benchmark_retrieval_modes.py +0 -123
- package/tools/vds-scripts/audit_orchestrator/tests/unit/scripts/test_verify_phase111_requirement_analysis.py +0 -409
- package/tools/vds-scripts/audit_orchestrator/tests/unit/seed/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/seed/test_seed_chain_cli.py +0 -277
- package/tools/vds-scripts/audit_orchestrator/tests/unit/seed/test_seed_loader.py +0 -502
- package/tools/vds-scripts/audit_orchestrator/tests/unit/skills/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/skills/test_skill_routing.py +0 -209
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sources/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sources/test_bitbucket_source.py +0 -66
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sources/test_non_retryable_markers.py +0 -88
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sources/test_repo_info.py +0 -212
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_completeness.py +0 -598
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_dispatch_events_contract_phase169.py +0 -100
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_dispatch_hardening_phase158.py +0 -392
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_dispatch_persistence_phase157.py +0 -914
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_embedding_client.py +0 -64
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_get_latest_completed_run.py +0 -313
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_heartbeat_phase169.py +0 -109
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_hybrid_search.py +0 -398
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_normalize_url.py +0 -262
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_phase152_query_surface.py +0 -59
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_phase98_confluence_document_model.py +0 -202
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_published_pages.py +0 -754
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_readiness_helpers.py +0 -193
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_run_ledger.py +0 -522
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_run_management.py +0 -378
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_schema_contract_phase170.py +0 -755
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_state_cmds.py +0 -231
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_state_loaders.py +0 -2151
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_state_run_api.py +0 -2226
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_store.py +0 -1435
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_store_dispatch.py +0 -646
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_store_dispatch_status_view.py +0 -181
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_store_scope.py +0 -213
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_utilization_persist_phase169.py +0 -77
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_vds_search.py +0 -263
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_vector_index_api.py +0 -319
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_vector_index_runtime.py +0 -175
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_vector_index_store.py +0 -1756
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sync/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sync/test_repo_sync.py +0 -257
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_artifact_exclusion.py +0 -119
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_auto_promote_phase158.py +0 -337
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_carry_forward_artifact_filtering.py +0 -317
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_checklist_precache_p160a.py +0 -416
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_cli_decomposition_fr219.py +0 -269
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_code_chunk_carry_forward.py +0 -203
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_config_coherence.py +0 -180
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_config_secret_policy.py +0 -522
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_corpus_project_id_migration.py +0 -318
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_corpus_status_diagnostics.py +0 -239
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_department_priority_ordering.py +0 -131
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_dispatch_coordinator_phase158.py +0 -402
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_dispatch_job_identity_p167a.py +0 -238
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_dispatch_ramp_up_phase171.py +0 -434
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_dispatcher.py +0 -911
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_doc_type_en_inference.py +0 -246
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_early_exit_unchunked_repos.py +0 -111
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_errors.py +0 -237
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_errors_taxonomy.py +0 -83
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_extract_chunking_config_phase98.py +0 -73
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_extract_cmds_state_helpers.py +0 -33
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_extract_docs_code_chunking.py +0 -260
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_finalize_dispatch_run_phase168.py +0 -341
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_identity.py +0 -221
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_infrastructure_detection.py +0 -441
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_junction_table_phase95.py +0 -259
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_late_binding_assignment_p167c.py +0 -286
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_misc_cmds_fr224_225_hardening.py +0 -194
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_p172_integration.py +0 -306
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_parent_provider_preflight.py +0 -118
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_performance_gates_phase92.py +0 -141
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_performance_gates_phase93.py +0 -50
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase115_search_strategy.py +0 -106
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase154_title_consistency.py +0 -117
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase155_param_forwarding.py +0 -304
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase158_concurrency_defaults.py +0 -207
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase170_doctor_schema.py +0 -319
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase170_regression.py +0 -334
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase94_corpus_lifecycle.py +0 -307
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase96_repo_key_migration.py +0 -305
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_pipelined_scheduling.py +0 -130
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_profile_availability_probe.py +0 -616
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_profile_aware_row_timeout.py +0 -102
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_profile_timeout_stagger_p160cd.py +0 -205
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_progress_summary_phase169.py +0 -96
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_registry_checklist_diagnostics.py +0 -124
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_resume_manifest_p167b.py +0 -268
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_risk_mitigations_p160e1.py +0 -348
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_single_row_shards_p160b.py +0 -357
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_state_repo_discovery.py +0 -504
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_sync_metadata_entries.py +0 -57
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_task_models.py +0 -1796
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_utilization_telemetry_p167e.py +0 -259
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_vietnamese_fts_hardening.py +0 -160
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_workflow_phase98_enrichment.py +0 -92
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_workflow_project_merge_materialization.py +0 -322
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_workflow_row_key_migration_guard.py +0 -88
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_workflow_short_circuit_phase121.py +0 -564
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_workflow_single_target_row_context.py +0 -49
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_zero_result_messaging.py +0 -76
- package/tools/vds-scripts/bandit-report.json +0 -2974
- package/tools/vds-scripts/brd_orchestrator/README.md +0 -29
- package/tools/vds-scripts/brd_orchestrator/pyproject.toml +0 -63
- package/tools/vds-scripts/brd_orchestrator/src/vds_brd_orchestrator/__init__.py +0 -17
- package/tools/vds-scripts/brd_orchestrator/src/vds_brd_orchestrator/cli.py +0 -187
- package/tools/vds-scripts/brd_orchestrator/src/vds_brd_orchestrator/validator.py +0 -121
- package/tools/vds-scripts/brd_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/brd_orchestrator/tests/test_cli.py +0 -62
- package/tools/vds-scripts/brd_orchestrator/tests/test_validator.py +0 -33
- package/tools/vds-scripts/circular_dependency_orchestrator/README.md +0 -30
- package/tools/vds-scripts/circular_dependency_orchestrator/pyproject.toml +0 -43
- package/tools/vds-scripts/circular_dependency_orchestrator/src/vds_circular_dependency_orchestrator/__init__.py +0 -16
- package/tools/vds-scripts/circular_dependency_orchestrator/src/vds_circular_dependency_orchestrator/cli.py +0 -904
- package/tools/vds-scripts/circular_dependency_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/circular_dependency_orchestrator/tests/unit/__init__.py +0 -0
- package/tools/vds-scripts/circular_dependency_orchestrator/tests/unit/test_cli.py +0 -354
- package/tools/vds-scripts/coverage.json +0 -1
- package/tools/vds-scripts/create_pr.py +0 -57
- package/tools/vds-scripts/diagram_generator/README.md +0 -663
- package/tools/vds-scripts/diagram_generator/ci_validate.sh +0 -16
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-component.png +0 -0
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-component.puml +0 -23
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-sequence.png +0 -0
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-sequence.puml +0 -21
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-usecase.png +0 -0
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-usecase.puml +0 -14
- package/tools/vds-scripts/diagram_generator/examples/github-actions-validate.yml +0 -39
- package/tools/vds-scripts/diagram_generator/generate_all_diagrams.py +0 -827
- package/tools/vds-scripts/diagram_generator/generate_insurance_c4_diagrams.py +0 -261
- package/tools/vds-scripts/diagram_generator/generate_insurance_c4_quick.py +0 -486
- package/tools/vds-scripts/diagram_generator/pyproject.toml +0 -28
- package/tools/vds-scripts/diagram_generator/render_png.py +0 -59
- package/tools/vds-scripts/diagram_generator/src/vds_diagram_generator/__init__.py +0 -3
- package/tools/vds-scripts/diagram_generator/src/vds_diagram_generator/cli.py +0 -50
- package/tools/vds-scripts/diagram_generator/test_c4_hierarchical.py +0 -142
- package/tools/vds-scripts/diagram_generator/test_c4_quick.py +0 -131
- package/tools/vds-scripts/diagram_generator/tests/__init__.py +0 -0
- package/tools/vds-scripts/diagram_generator/tests/test_analyzer_completeness.py +0 -260
- package/tools/vds-scripts/diagram_generator/tests/test_c4_syntax_correctness.py +0 -138
- package/tools/vds-scripts/diagram_generator/tests/test_component_coverage.py +0 -182
- package/tools/vds-scripts/diagram_generator/tests/test_mermaid_output.py +0 -80
- package/tools/vds-scripts/diagram_generator/tests/test_png_generation.py +0 -112
- package/tools/vds-scripts/diagram_generator/tests/test_scenario_templates.py +0 -15
- package/tools/vds-scripts/diagram_generator/tests/test_sequence_accuracy.py +0 -93
- package/tools/vds-scripts/diagram_generator/tests/test_structurizr_export.py +0 -177
- package/tools/vds-scripts/diagram_generator/tests/test_style_consistency.py +0 -174
- package/tools/vds-scripts/diagram_generator/tests/test_usecase_generator.py +0 -201
- package/tools/vds-scripts/diagram_generator/tests/test_usecase_integration.py +0 -124
- package/tools/vds-scripts/docker/compose.phase2-verification.yml +0 -31
- package/tools/vds-scripts/docker-compose.openapi-validator.yml +0 -14
- package/tools/vds-scripts/excel_orchestrator/README.md +0 -288
- package/tools/vds-scripts/excel_orchestrator/RESEARCH_BASED_UPDATES_REPORT.md +0 -261
- package/tools/vds-scripts/excel_orchestrator/add_essential_missing_effort.py +0 -255
- package/tools/vds-scripts/excel_orchestrator/adjust_effort_complexity.py +0 -184
- package/tools/vds-scripts/excel_orchestrator/brd_analysis_and_task_breakdown.py +0 -632
- package/tools/vds-scripts/excel_orchestrator/brd_analysis_comprehensive.py +0 -1029
- package/tools/vds-scripts/excel_orchestrator/check_overlaps_and_brd_coverage.py +0 -570
- package/tools/vds-scripts/excel_orchestrator/clean_remarks_column.py +0 -127
- package/tools/vds-scripts/excel_orchestrator/comprehensive_brd_check.py +0 -322
- package/tools/vds-scripts/excel_orchestrator/create_buffered_summary.py +0 -119
- package/tools/vds-scripts/excel_orchestrator/create_service_totals_sheet.py +0 -118
- package/tools/vds-scripts/excel_orchestrator/examples/basic_operations.py +0 -85
- package/tools/vds-scripts/excel_orchestrator/expand_all_tasks.py +0 -341
- package/tools/vds-scripts/excel_orchestrator/expand_tasks.py +0 -304
- package/tools/vds-scripts/excel_orchestrator/fill_brd_references.py +0 -347
- package/tools/vds-scripts/excel_orchestrator/fill_remarks_and_colors.py +0 -132
- package/tools/vds-scripts/excel_orchestrator/finalize_brd_and_cleanup.py +0 -295
- package/tools/vds-scripts/excel_orchestrator/finalize_brd_coverage.py +0 -327
- package/tools/vds-scripts/excel_orchestrator/fix_all_formulas.py +0 -99
- package/tools/vds-scripts/excel_orchestrator/fix_detail_presentation.py +0 -113
- package/tools/vds-scripts/excel_orchestrator/fix_presentation_and_effort.py +0 -116
- package/tools/vds-scripts/excel_orchestrator/fix_presentation_consistency.py +0 -231
- package/tools/vds-scripts/excel_orchestrator/fix_remarks_matching.py +0 -179
- package/tools/vds-scripts/excel_orchestrator/group_tasks_by_service_id.py +0 -210
- package/tools/vds-scripts/excel_orchestrator/increase_brd_coverage.py +0 -497
- package/tools/vds-scripts/excel_orchestrator/increase_effort_complexity.py +0 -155
- package/tools/vds-scripts/excel_orchestrator/organize_and_deduplicate.py +0 -273
- package/tools/vds-scripts/excel_orchestrator/pyproject.toml +0 -64
- package/tools/vds-scripts/excel_orchestrator/rebuild_all_formulas.py +0 -146
- package/tools/vds-scripts/excel_orchestrator/remove_base_multiplier_and_check_duplicates.py +0 -310
- package/tools/vds-scripts/excel_orchestrator/remove_duplicate_brd_tasks.py +0 -137
- package/tools/vds-scripts/excel_orchestrator/research_based_updates.py +0 -457
- package/tools/vds-scripts/excel_orchestrator/restore_e_values.py +0 -172
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/__init__.py +0 -5
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/cli.py +0 -746
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/config.py +0 -74
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/converters.py +0 -226
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/errors.py +0 -88
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/excel_client.py +0 -443
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/formatters.py +0 -211
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/logging.py +0 -57
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/source_contract.py +0 -29
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/target_state_status.py +0 -837
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/ulnc_alignment.py +0 -1291
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/validators.py +0 -164
- package/tools/vds-scripts/excel_orchestrator/sync_detail_and_total_sheets.py +0 -211
- package/tools/vds-scripts/excel_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/excel_orchestrator/tests/conftest.py +0 -36
- package/tools/vds-scripts/excel_orchestrator/tests/test_cli.py +0 -383
- package/tools/vds-scripts/excel_orchestrator/tests/test_excel_client.py +0 -129
- package/tools/vds-scripts/excel_orchestrator/tests/test_ulnc_alignment.py +0 -373
- package/tools/vds-scripts/excel_orchestrator/tests/test_validators.py +0 -64
- package/tools/vds-scripts/excel_orchestrator/update_api_database_effort.py +0 -261
- package/tools/vds-scripts/excel_orchestrator/update_buffers_inline.py +0 -115
- package/tools/vds-scripts/excel_orchestrator/update_complex_services_and_add_new.py +0 -336
- package/tools/vds-scripts/excel_orchestrator/update_responsibility_and_fix_rows.py +0 -208
- package/tools/vds-scripts/excel_orchestrator/update_task_breakdown_vietnamese.py +0 -309
- package/tools/vds-scripts/excel_orchestrator/update_vietnamese_and_responsibility.py +0 -415
- package/tools/vds-scripts/excel_orchestrator/verify_brd_coverage_comprehensive.py +0 -401
- package/tools/vds-scripts/hexagonal_orchestrator/README.md +0 -530
- package/tools/vds-scripts/hexagonal_orchestrator/pyproject.toml +0 -48
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/__init__.py +0 -39
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/analyzers/__init__.py +0 -19
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/analyzers/base.py +0 -95
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/analyzers/fallback.py +0 -614
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/analyzers/java.py +0 -372
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/analyzers/python.py +0 -437
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/cache.py +0 -331
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/classifier.py +0 -263
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/cli.py +0 -554
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/config.py +0 -577
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/models.py +0 -159
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/profiler.py +0 -451
- package/tools/vds-scripts/hexagonal_orchestrator/test-config.yaml +0 -38
- package/tools/vds-scripts/hexagonal_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/adapter/driven/persistence/InMemoryUserRepository.java +0 -62
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/adapter/driving/api/UserController.java +0 -101
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/application/port/EmailService.java +0 -33
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/application/port/UserRepository.java +0 -45
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/application/usecase/CreateUser.java +0 -58
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/domain/entity/Email.java +0 -80
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/domain/entity/User.java +0 -98
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-noncompliant/domain/User.java +0 -64
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-with-frameworks/domain/Menu.java +0 -13
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-with-frameworks/domain/Product.java +0 -16
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/application/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/application/ports/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/application/ports/email_service.py +0 -60
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/application/ports/user_repository.py +0 -78
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/domain/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/domain/entities/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/domain/entities/user.py +0 -56
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/domain/value_objects/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/domain/value_objects/email.py +0 -63
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-noncompliant/application/user_service.py +0 -1837
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-noncompliant/domain/user.py +0 -43
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_cache.py +0 -458
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_cli_integration.py +0 -942
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_cli_unit.py +0 -557
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_cross_repo_pollution.py +0 -275
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_foundation.py +0 -129
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_integration.py +0 -1524
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_java_analyzer.py +0 -642
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_timing_unit.py +0 -60
- package/tools/vds-scripts/intellij_orchestrator/README.md +0 -55
- package/tools/vds-scripts/intellij_orchestrator/pyproject.toml +0 -64
- package/tools/vds-scripts/intellij_orchestrator/src/vds_intellij_orchestrator/__init__.py +0 -17
- package/tools/vds-scripts/intellij_orchestrator/src/vds_intellij_orchestrator/cli.py +0 -210
- package/tools/vds-scripts/intellij_orchestrator/src/vds_intellij_orchestrator/core.py +0 -260
- package/tools/vds-scripts/intellij_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/intellij_orchestrator/tests/test_cli.py +0 -112
- package/tools/vds-scripts/intellij_orchestrator/tests/test_core.py +0 -83
- package/tools/vds-scripts/links_orchestrator/README.md +0 -63
- package/tools/vds-scripts/links_orchestrator/pyproject.toml +0 -64
- package/tools/vds-scripts/links_orchestrator/src/vds_links_orchestrator/__init__.py +0 -10
- package/tools/vds-scripts/links_orchestrator/src/vds_links_orchestrator/cli.py +0 -254
- package/tools/vds-scripts/links_orchestrator/src/vds_links_orchestrator/validator.py +0 -244
- package/tools/vds-scripts/links_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/links_orchestrator/tests/test_cli.py +0 -128
- package/tools/vds-scripts/links_orchestrator/tests/test_validator.py +0 -76
- package/tools/vds-scripts/lsp_orchestrator/.dockerignore +0 -69
- package/tools/vds-scripts/lsp_orchestrator/ARCHITECTURE.md +0 -383
- package/tools/vds-scripts/lsp_orchestrator/CODE_QUALITY_IMPROVEMENTS.md +0 -196
- package/tools/vds-scripts/lsp_orchestrator/COMMANDS.md +0 -870
- package/tools/vds-scripts/lsp_orchestrator/Dockerfile +0 -59
- package/tools/vds-scripts/lsp_orchestrator/IMPLEMENTATION_SUMMARY.md +0 -490
- package/tools/vds-scripts/lsp_orchestrator/LSP_ISSUES_AND_FINDINGS.md +0 -380
- package/tools/vds-scripts/lsp_orchestrator/README.md +0 -616
- package/tools/vds-scripts/lsp_orchestrator/SETUP.md +0 -143
- package/tools/vds-scripts/lsp_orchestrator/TEST_COVERAGE_SUMMARY.md +0 -255
- package/tools/vds-scripts/lsp_orchestrator/VERIFICATION_CHECKLIST.md +0 -814
- package/tools/vds-scripts/lsp_orchestrator/docker-compose.yml +0 -102
- package/tools/vds-scripts/lsp_orchestrator/docs/FOR_LLMS.md +0 -401
- package/tools/vds-scripts/lsp_orchestrator/docs/explanation/lsp-response-matching.md +0 -79
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/automate-with-json.md +0 -159
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/docker-mode.md +0 -256
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/navigate-code.md +0 -116
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/parallel-processing.md +0 -179
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/project-tool-detection.md +0 -320
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/type-check-code.md +0 -46
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/use-daemon-mode.md +0 -78
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/wsl2-optimization.md +0 -227
- package/tools/vds-scripts/lsp_orchestrator/docs/index.md +0 -88
- package/tools/vds-scripts/lsp_orchestrator/docs/operator-hover-definition.md +0 -143
- package/tools/vds-scripts/lsp_orchestrator/docs/reference/commands.md +0 -581
- package/tools/vds-scripts/lsp_orchestrator/docs/reference/configuration.md +0 -422
- package/tools/vds-scripts/lsp_orchestrator/docs/tutorials/00-quick-start.md +0 -169
- package/tools/vds-scripts/lsp_orchestrator/pyproject.toml +0 -63
- package/tools/vds-scripts/lsp_orchestrator/src/test_file.py +0 -5
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/__init__.py +0 -3
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/aggregator.py +0 -340
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/basedpyright_runner.py +0 -167
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/cli.py +0 -3370
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/code_actions.py +0 -79
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/core.py +0 -3295
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/daemon_client.py +0 -672
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/daemon_manager.py +0 -577
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/daemon_server.py +0 -1040
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/detectors/__init__.py +0 -9
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/detectors/project_detector.py +0 -537
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/formatters.py +0 -141
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/ipc_protocol.py +0 -225
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/lsp_client.py +0 -957
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/lsp_router.py +0 -335
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/mcp_server.py +0 -181
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/models/__init__.py +0 -201
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/models/project_detector.py +0 -646
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/models/project_tools.py +0 -114
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/models.py +0 -399
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/mypy_runner.py +0 -209
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/protocols.py +0 -52
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/ruff_lsp_client.py +0 -109
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/ruff_runner.py +0 -44
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/utils.py +0 -959
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/workspace_indexer.py +0 -1037
- package/tools/vds-scripts/lsp_orchestrator/test_workspace_lsp.py +0 -6
- package/tools/vds-scripts/lsp_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/lsp_orchestrator/tests/conftest.py +0 -6
- package/tools/vds-scripts/lsp_orchestrator/tests/test_aggregator.py +0 -59
- package/tools/vds-scripts/lsp_orchestrator/tests/test_cli.py +0 -111
- package/tools/vds-scripts/lsp_orchestrator/tests/test_detect_tools_command.py +0 -186
- package/tools/vds-scripts/lsp_orchestrator/tests/test_formatter_linter_detection.py +0 -519
- package/tools/vds-scripts/lsp_orchestrator/tests/test_integration_phase9_10_11.py +0 -367
- package/tools/vds-scripts/lsp_orchestrator/tests/test_mypy_runner.py +0 -482
- package/tools/vds-scripts/lsp_orchestrator/tests/test_package_manager_detection.py +0 -399
- package/tools/vds-scripts/lsp_orchestrator/tests/test_phase10.py +0 -389
- package/tools/vds-scripts/lsp_orchestrator/tests/test_phase11.py +0 -327
- package/tools/vds-scripts/lsp_orchestrator/tests/test_phase12_integration.py +0 -634
- package/tools/vds-scripts/lsp_orchestrator/tests/test_phase9.py +0 -196
- package/tools/vds-scripts/lsp_orchestrator/tests/test_project_detector.py +0 -377
- package/tools/vds-scripts/lsp_orchestrator/tests/test_test_runner_detection.py +0 -549
- package/tools/vds-scripts/lsp_orchestrator/tests/test_type_checker_routing.py +0 -362
- package/tools/vds-scripts/lsp_orchestrator/tests/test_workspace_indexer.py +0 -144
- package/tools/vds-scripts/markdown_orchestrator/README.md +0 -72
- package/tools/vds-scripts/markdown_orchestrator/pyproject.toml +0 -39
- package/tools/vds-scripts/markdown_orchestrator/src/vds_markdown_orchestrator/__init__.py +0 -5
- package/tools/vds-scripts/markdown_orchestrator/src/vds_markdown_orchestrator/cli.py +0 -102
- package/tools/vds-scripts/multi_agent_orchestrator/Dockerfile +0 -65
- package/tools/vds-scripts/multi_agent_orchestrator/README.md +0 -306
- package/tools/vds-scripts/multi_agent_orchestrator/postman/README.md +0 -264
- package/tools/vds-scripts/multi_agent_orchestrator/postman/TEST_RESULTS_SUMMARY.md +0 -197
- package/tools/vds-scripts/multi_agent_orchestrator/postman/VDS-Multi-Agent-Orchestrator-API.postman_collection.json +0 -1010
- package/tools/vds-scripts/multi_agent_orchestrator/postman/environments/local-development.postman_environment.json +0 -55
- package/tools/vds-scripts/multi_agent_orchestrator/postman/test-results.json +0 -24146
- package/tools/vds-scripts/multi_agent_orchestrator/pyproject.toml +0 -63
- package/tools/vds-scripts/multi_agent_orchestrator/run_api.py +0 -9
- package/tools/vds-scripts/multi_agent_orchestrator/run_mock_api.py +0 -9
- package/tools/vds-scripts/multi_agent_orchestrator/simple_test.py +0 -53
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/__init__.py +0 -25
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/agent_pool.py +0 -433
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/api/__init__.py +0 -5
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/api/main.py +0 -722
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/api/mock_main.py +0 -812
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/change_log.py +0 -515
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/cli.py +0 -424
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/config.py +0 -220
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/conflict_resolver.py +0 -462
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/coordinator.py +0 -627
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/models.py +0 -389
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/progress_dashboard.py +0 -380
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/redis_client.py +0 -245
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/scheduler_subscriber.py +0 -272
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/task_manager.py +0 -536
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/task_tracking.py +0 -550
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/vds_ai_memory_client.py +0 -352
- package/tools/vds-scripts/multi_agent_orchestrator/test_complete_system.py +0 -149
- package/tools/vds-scripts/multi_agent_orchestrator/test_infrastructure_only.py +0 -194
- package/tools/vds-scripts/multi_agent_orchestrator/test_integration.py +0 -108
- package/tools/vds-scripts/multi_agent_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/multi_agent_orchestrator/tests/test_agent_registration_credential_validator.py +0 -223
- package/tools/vds-scripts/multi_agent_orchestrator/tests/test_config.py +0 -210
- package/tools/vds-scripts/multi_agent_orchestrator/tests/test_models.py +0 -195
- package/tools/vds-scripts/multi_agent_orchestrator/tests/test_w9_agent_routes.py +0 -321
- package/tools/vds-scripts/openapi_orchestrator/README.md +0 -197
- package/tools/vds-scripts/openapi_orchestrator/pyproject.toml +0 -106
- package/tools/vds-scripts/openapi_orchestrator/src/vds_openapi_orchestrator/__init__.py +0 -29
- package/tools/vds-scripts/openapi_orchestrator/src/vds_openapi_orchestrator/cli.py +0 -345
- package/tools/vds-scripts/openapi_orchestrator/src/vds_openapi_orchestrator/full_validator.py +0 -183
- package/tools/vds-scripts/openapi_orchestrator/src/vds_openapi_orchestrator/spec_validator.py +0 -197
- package/tools/vds-scripts/openapi_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/openapi_orchestrator/tests/test_cli.py +0 -234
- package/tools/vds-scripts/openapi_orchestrator/tests/test_full_validator.py +0 -203
- package/tools/vds-scripts/openapi_orchestrator/tests/test_spec_validator.py +0 -295
- package/tools/vds-scripts/pdf_orchestrator/.dockerignore +0 -93
- package/tools/vds-scripts/pdf_orchestrator/.env.example +0 -40
- package/tools/vds-scripts/pdf_orchestrator/.ruff_rules.py +0 -350
- package/tools/vds-scripts/pdf_orchestrator/.yamllint.yml +0 -43
- package/tools/vds-scripts/pdf_orchestrator/DEVELOPMENT_PLAN.md +0 -80
- package/tools/vds-scripts/pdf_orchestrator/Dockerfile +0 -87
- package/tools/vds-scripts/pdf_orchestrator/README.md +0 -608
- package/tools/vds-scripts/pdf_orchestrator/cli_verification_test/test.md +0 -6
- package/tools/vds-scripts/pdf_orchestrator/cli_verification_test/test.pdf +0 -0
- package/tools/vds-scripts/pdf_orchestrator/config/alertmanager.yml +0 -83
- package/tools/vds-scripts/pdf_orchestrator/config/prometheus.prod.yml +0 -98
- package/tools/vds-scripts/pdf_orchestrator/config/prometheus.yml +0 -40
- package/tools/vds-scripts/pdf_orchestrator/config/redis.conf +0 -78
- package/tools/vds-scripts/pdf_orchestrator/docs/COMPETITIVE_ANALYSIS_REPORT.md +0 -309
- package/tools/vds-scripts/pdf_orchestrator/docs/FEATURES_GUIDE.md +0 -518
- package/tools/vds-scripts/pdf_orchestrator/docs/MULTI_USER_DEPLOYMENT_GUIDE.md +0 -615
- package/tools/vds-scripts/pdf_orchestrator/docs/USER_GUIDE.md +0 -829
- package/tools/vds-scripts/pdf_orchestrator/pyproject.toml +0 -87
- package/tools/vds-scripts/pdf_orchestrator/pytest.ini +0 -71
- package/tools/vds-scripts/pdf_orchestrator/ruff.toml +0 -6
- package/tools/vds-scripts/pdf_orchestrator/scripts/debug_security_report.py +0 -59
- package/tools/vds-scripts/pdf_orchestrator/scripts/demo_library_selector.py +0 -109
- package/tools/vds-scripts/pdf_orchestrator/scripts/generate_project_stats.py +0 -52
- package/tools/vds-scripts/pdf_orchestrator/scripts/generate_styled_pdf.py +0 -95
- package/tools/vds-scripts/pdf_orchestrator/scripts/migrate_render_pdfs.py +0 -285
- package/tools/vds-scripts/pdf_orchestrator/scripts/setup_team.bat +0 -283
- package/tools/vds-scripts/pdf_orchestrator/scripts/setup_team.sh +0 -324
- package/tools/vds-scripts/pdf_orchestrator/src/vds_pdf_orchestrator/__init__.py +0 -5
- package/tools/vds-scripts/pdf_orchestrator/src/vds_pdf_orchestrator/cli.py +0 -542
- package/tools/vds-scripts/pdf_orchestrator/src/vds_pdf_orchestrator/config.py +0 -33
- package/tools/vds-scripts/pdf_orchestrator/tests/README.md +0 -650
- package/tools/vds-scripts/pdf_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/pdf_orchestrator/tests/conftest.py +0 -520
- package/tools/vds-scripts/pdf_orchestrator/tests/requirements.txt +0 -51
- package/tools/vds-scripts/pdf_orchestrator/tests/run_tests.py +0 -659
- package/tools/vds-scripts/pdf_orchestrator/tests/test_config.py +0 -36
- package/tools/vds-scripts/progress_report_orchestrator/Dockerfile +0 -77
- package/tools/vds-scripts/progress_report_orchestrator/README.md +0 -39
- package/tools/vds-scripts/progress_report_orchestrator/alembic/env.py +0 -42
- package/tools/vds-scripts/progress_report_orchestrator/alembic/script.py.mako +0 -28
- package/tools/vds-scripts/progress_report_orchestrator/alembic/versions/0001_initial_progress_schema.py +0 -180
- package/tools/vds-scripts/progress_report_orchestrator/alembic.ini +0 -67
- package/tools/vds-scripts/progress_report_orchestrator/pyproject.toml +0 -67
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/__init__.py +0 -3
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/analyzers/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/analyzers/endpoint_scanner.py +0 -238
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/analyzers/git_activity.py +0 -159
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/analyzers/hexagonal.py +0 -100
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/analyzers/test_scanner.py +0 -136
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/cli.py +0 -743
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/config.py +0 -50
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/db/__init__.py +0 -12
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/db/alembic_filters.py +0 -64
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/memory.py +0 -82
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/models/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/models/analysis.py +0 -84
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/models/report.py +0 -117
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/models/topology.py +0 -101
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/parsers/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/parsers/kg_parser.py +0 -252
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/parsers/uc_reader.py +0 -159
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/concurrency.py +0 -39
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/llm_eval.py +0 -570
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/report.py +0 -1256
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/structural.py +0 -384
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/sync.py +0 -143
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/recommendations/__init__.py +0 -5
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/recommendations/engine.py +0 -105
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/recommendations/templates.py +0 -236
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/scheduler_subscriber.py +0 -238
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/skills/README.md +0 -56
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/skills/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/skills/srs-architecture-reviewer/SKILL.md +0 -67
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/skills/srs-endpoint-matcher/SKILL.md +0 -67
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/state/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/state/schema.py +0 -625
- package/tools/vds-scripts/progress_report_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/__init__.py +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/.gitkeep +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/__init__.py +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/doc-dependencies.yaml +0 -79
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/fr-to-docs.yaml +0 -478
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/fr-to-services.yaml +0 -18
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/registry.yaml +0 -346
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/phase3_baseline_standard.md +0 -564
- package/tools/vds-scripts/progress_report_orchestrator/tests/integration/__init__.py +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/integration/test_checkpoint.py +0 -276
- package/tools/vds-scripts/progress_report_orchestrator/tests/test_alembic_migrations.py +0 -265
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/__init__.py +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_analyzers.py +0 -267
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_bounded_gather.py +0 -176
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_cli_phase_report.py +0 -119
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_delta.py +0 -169
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_error_handling.py +0 -150
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_gate_exit_codes.py +0 -230
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_git_activity.py +0 -215
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_kg_parser.py +0 -267
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_llm_autodetect.py +0 -183
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_llm_eval.py +0 -529
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_memory_integration.py +0 -151
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_migration_contract.py +0 -254
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_mode_rendering.py +0 -576
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_models.py +0 -251
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_progress_llm_config.py +0 -67
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_recommendations.py +0 -480
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_report_enhancements.py +0 -415
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_resume_reload.py +0 -343
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_trend_regression.py +0 -294
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_uc_reader.py +0 -169
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_valence_gap.py +0 -293
- package/tools/vds-scripts/project-cycle-report.json +0 -14
- package/tools/vds-scripts/project-dependency-graph.json +0 -11361
- package/tools/vds-scripts/project-topology.json +0 -99
- package/tools/vds-scripts/public_interface_boundary_orchestrator/pyproject.toml +0 -18
- package/tools/vds-scripts/public_interface_boundary_orchestrator/src/vds_public_interface_boundary_orchestrator/__init__.py +0 -0
- package/tools/vds-scripts/public_interface_boundary_orchestrator/src/vds_public_interface_boundary_orchestrator/cli.py +0 -232
- package/tools/vds-scripts/public_interface_boundary_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/public_interface_boundary_orchestrator/tests/test_cli.py +0 -108
- package/tools/vds-scripts/research_orchestrator/README.md +0 -68
- package/tools/vds-scripts/research_orchestrator/py.typed +0 -0
- package/tools/vds-scripts/research_orchestrator/pyproject.toml +0 -95
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/__init__.py +0 -3
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/_env.py +0 -11
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/cli.py +0 -335
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/config.py +0 -43
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/evidence/__init__.py +0 -0
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/evidence/models.py +0 -89
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/evidence/scoring.py +0 -102
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/exceptions.py +0 -78
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/http_client.py +0 -160
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/logging.py +0 -49
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/output/__init__.py +0 -0
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/output/formatters.py +0 -93
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/py.typed +0 -1
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/report/__init__.py +0 -0
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/report/build.py +0 -156
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/report/format.py +0 -147
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/tools/__init__.py +0 -0
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/tools/health.py +0 -66
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/tools/health_graph.py +0 -52
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/tools/registry.py +0 -127
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/tools/search.py +0 -230
- package/tools/vds-scripts/research_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/research_orchestrator/tests/conftest.py +0 -53
- package/tools/vds-scripts/research_orchestrator/tests/test_cli.py +0 -222
- package/tools/vds-scripts/research_orchestrator/tests/test_config.py +0 -23
- package/tools/vds-scripts/research_orchestrator/tests/test_exceptions.py +0 -62
- package/tools/vds-scripts/research_orchestrator/tests/test_formatters.py +0 -89
- package/tools/vds-scripts/research_orchestrator/tests/test_graph_integration.py +0 -149
- package/tools/vds-scripts/research_orchestrator/tests/test_http_client.py +0 -134
- package/tools/vds-scripts/research_orchestrator/tests/test_report_build.py +0 -128
- package/tools/vds-scripts/research_orchestrator/tests/test_report_format.py +0 -91
- package/tools/vds-scripts/research_orchestrator/tests/test_scoring.py +0 -95
- package/tools/vds-scripts/research_orchestrator/tests/vds_research_orchestrator/test_tools/__init__.py +0 -1
- package/tools/vds-scripts/research_orchestrator/tests/vds_research_orchestrator/test_tools/test_health.py +0 -139
- package/tools/vds-scripts/research_orchestrator/tests/vds_research_orchestrator/test_tools/test_registry.py +0 -135
- package/tools/vds-scripts/research_orchestrator/tests/vds_research_orchestrator/test_tools/test_search.py +0 -238
- package/tools/vds-scripts/run-history.json +0 -26
- package/tools/vds-scripts/schema_converter/README.md +0 -109
- package/tools/vds-scripts/schema_converter/pyproject.toml +0 -37
- package/tools/vds-scripts/schema_converter/src/vds_schema_converter/__init__.py +0 -3
- package/tools/vds-scripts/schema_converter/src/vds_schema_converter/cli.py +0 -50
- package/tools/vds-scripts/schema_converter/tests/__init__.py +0 -0
- package/tools/vds-scripts/schema_converter/tests/test_json_schema_generator.py +0 -115
- package/tools/vds-scripts/schema_converter/tests/test_mermaid_generator.py +0 -112
- package/tools/vds-scripts/schema_converter/tests/test_parser.py +0 -111
- package/tools/vds-scripts/schema_converter/tests/test_plantuml_generator.py +0 -112
- package/tools/vds-scripts/schema_converter/tests/test_plantuml_validator.py +0 -69
- package/tools/vds-scripts/schema_converter/tests/test_prisma_generator.py +0 -113
- package/tools/vds-scripts/schema_converter/tests/test_sql_generator.py +0 -138
- package/tools/vds-scripts/schema_converter/tests/test_typeorm_generator.py +0 -110
- package/tools/vds-scripts/schema_converter/tests/test_validators.py +0 -96
- package/tools/vds-scripts/spec_orchestrator/README.md +0 -13
- package/tools/vds-scripts/spec_orchestrator/pyproject.toml +0 -40
- package/tools/vds-scripts/spec_orchestrator/src/vds_spec_orchestrator/__init__.py +0 -5
- package/tools/vds-scripts/spec_orchestrator/src/vds_spec_orchestrator/cli.py +0 -162
- package/tools/vds-scripts/spec_orchestrator/src/vds_spec_orchestrator/core.py +0 -575
- package/tools/vds-scripts/spec_orchestrator/src/vds_spec_orchestrator/sync.py +0 -306
- package/tools/vds-scripts/spec_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/spec_orchestrator/tests/test_frontmatter_drift.py +0 -243
- package/tools/vds-scripts/spec_orchestrator/tests/test_sync.py +0 -342
- package/tools/vds-scripts/structure_orchestrator/README.md +0 -60
- package/tools/vds-scripts/structure_orchestrator/pyproject.toml +0 -103
- package/tools/vds-scripts/structure_orchestrator/src/vds_structure_orchestrator/__init__.py +0 -13
- package/tools/vds-scripts/structure_orchestrator/src/vds_structure_orchestrator/cli.py +0 -308
- package/tools/vds-scripts/structure_orchestrator/src/vds_structure_orchestrator/validator.py +0 -257
- package/tools/vds-scripts/structure_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/structure_orchestrator/tests/test_cli.py +0 -161
- package/tools/vds-scripts/structure_orchestrator/tests/test_helpers.py +0 -115
- package/tools/vds-scripts/structure_orchestrator/tests/test_validator.py +0 -104
- package/tools/vds-scripts/task_orchestrator/README.md +0 -50
- package/tools/vds-scripts/task_orchestrator/__init__.py +0 -18
- package/tools/vds-scripts/task_orchestrator/pyproject.toml +0 -43
- package/tools/vds-scripts/task_orchestrator/scripts/run_excel_sync.py +0 -36
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/__init__.py +0 -13
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/audit.py +0 -134
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/cli.py +0 -127
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/debug.py +0 -133
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/normalize.py +0 -113
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/refine.py +0 -201
- package/tools/vds-scripts/task_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/task_orchestrator/tests/test_task_orchestrator.py +0 -84
- package/tools/vds-scripts/temp_query_projects.py +0 -2
- package/tools/vds-scripts/test_small.md +0 -1
- package/tools/vds-scripts/text_utils_orchestrator/pyproject.toml +0 -20
- package/tools/vds-scripts/text_utils_orchestrator/src/vds_text_utils/__init__.py +0 -7
- package/tools/vds-scripts/text_utils_orchestrator/src/vds_text_utils/i18n.py +0 -143
- package/tools/vds-scripts/text_utils_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/text_utils_orchestrator/tests/test_i18n.py +0 -53
- package/tools/vds-scripts/upgrade_major.py +0 -61
- package/tools/vds-scripts/upgrade_major_v2.py +0 -64
- package/tools/vds-scripts/verify_violations.py +0 -57
- package/tools/vds-scripts/workflow-summary.json +0 -325
- package/tools/vds-scripts/workflow-summary.md +0 -8
|
@@ -1,2736 +0,0 @@
|
|
|
1
|
-
"""Unit tests for MaterialCompletenessService (Phase 126, TSK-126.1, TSK-126.15).
|
|
2
|
-
|
|
3
|
-
Comprehensive unit tests for the material completeness checking service covering:
|
|
4
|
-
- Service construction and initialization
|
|
5
|
-
- Requirement discovery from multiple sources
|
|
6
|
-
- Cache validation for different material types
|
|
7
|
-
- Metrics computation
|
|
8
|
-
- Action generation
|
|
9
|
-
- Helper methods
|
|
10
|
-
- Main entry point workflow
|
|
11
|
-
|
|
12
|
-
Reference: .kiro/specs/audit-orchestrator/requirements.md FR-126.1
|
|
13
|
-
Phase 126 Package A (TSK-126.1) + Package E (TSK-126.15)
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
from __future__ import annotations
|
|
17
|
-
|
|
18
|
-
from datetime import UTC, datetime, timedelta
|
|
19
|
-
from pathlib import Path
|
|
20
|
-
from typing import Any
|
|
21
|
-
from unittest.mock import AsyncMock, MagicMock, patch
|
|
22
|
-
|
|
23
|
-
import pytest
|
|
24
|
-
from vds_audit_orchestrator.collectors.completeness.material_completeness_service import (
|
|
25
|
-
MaterialCompletenessService,
|
|
26
|
-
RequirementDiscoveryError,
|
|
27
|
-
)
|
|
28
|
-
from vds_audit_orchestrator.collectors.material_cache import MaterialCache
|
|
29
|
-
from vds_audit_orchestrator.models.completeness import (
|
|
30
|
-
CompletenessMetrics,
|
|
31
|
-
CompletenessReport,
|
|
32
|
-
FreshnessTier,
|
|
33
|
-
MaterialRequirement,
|
|
34
|
-
MaterialType,
|
|
35
|
-
MissingMaterial,
|
|
36
|
-
PreparedMaterial,
|
|
37
|
-
StaleMaterial,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
# ===========================================================================
|
|
41
|
-
# Helpers
|
|
42
|
-
# ===========================================================================
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def _make_state_store(
|
|
46
|
-
project_links: list[dict] | None = None,
|
|
47
|
-
project_preparation: dict | None = None,
|
|
48
|
-
) -> MagicMock:
|
|
49
|
-
"""Create a mock PostgresStateStore."""
|
|
50
|
-
store = MagicMock()
|
|
51
|
-
store.get_project_links = AsyncMock(return_value=project_links or [])
|
|
52
|
-
store.get_project_preparation = AsyncMock(return_value=project_preparation or {})
|
|
53
|
-
return store
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def _make_cache() -> MaterialCache:
|
|
57
|
-
"""Create a test MaterialCache."""
|
|
58
|
-
return MaterialCache(cache_dir=Path("/tmp/test_cache"))
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def _make_registry_parser(enabled: bool = True) -> MagicMock | None:
|
|
62
|
-
"""Create a mock RegistryPageParser."""
|
|
63
|
-
if not enabled:
|
|
64
|
-
return None
|
|
65
|
-
parser = MagicMock()
|
|
66
|
-
parser.parse_page_links = AsyncMock(return_value=[])
|
|
67
|
-
return parser
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def _make_requirement(
|
|
71
|
-
material_type: MaterialType = MaterialType.page,
|
|
72
|
-
identifier: str = "88718940",
|
|
73
|
-
project_key: str = "CEP",
|
|
74
|
-
source: str = "registry",
|
|
75
|
-
priority: int = 10,
|
|
76
|
-
title: str | None = None,
|
|
77
|
-
) -> MaterialRequirement:
|
|
78
|
-
"""Create a MaterialRequirement for testing."""
|
|
79
|
-
return MaterialRequirement(
|
|
80
|
-
material_type=material_type,
|
|
81
|
-
identifier=identifier,
|
|
82
|
-
project_key=project_key,
|
|
83
|
-
source=source,
|
|
84
|
-
priority=priority,
|
|
85
|
-
title=title or f"Test {material_type.value}",
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def _make_cache_entry(
|
|
90
|
-
material_type: MaterialType = MaterialType.page,
|
|
91
|
-
identifier: str = "88718940",
|
|
92
|
-
age_hours: float = 2.0,
|
|
93
|
-
version: str | None = None,
|
|
94
|
-
) -> dict[str, Any]:
|
|
95
|
-
"""Create a mock cache entry."""
|
|
96
|
-
now = datetime.now(UTC)
|
|
97
|
-
cached_at = now - timedelta(hours=age_hours)
|
|
98
|
-
|
|
99
|
-
if material_type == MaterialType.page:
|
|
100
|
-
entry = {
|
|
101
|
-
"page_id": identifier,
|
|
102
|
-
"cached_at": cached_at.isoformat(),
|
|
103
|
-
"title": "Cached page",
|
|
104
|
-
"project_key": "CEP",
|
|
105
|
-
}
|
|
106
|
-
elif material_type == MaterialType.attachment:
|
|
107
|
-
entry = {
|
|
108
|
-
"attachment_id": identifier,
|
|
109
|
-
"page_id": "88718940", # Attachments always have a page_id
|
|
110
|
-
"cached_at": cached_at.isoformat(),
|
|
111
|
-
"title": "Cached attachment",
|
|
112
|
-
"project_key": "CEP",
|
|
113
|
-
"cache_paths": {},
|
|
114
|
-
"hashes": {},
|
|
115
|
-
}
|
|
116
|
-
else: # repo
|
|
117
|
-
entry = {
|
|
118
|
-
"repo": identifier,
|
|
119
|
-
"cached_at": cached_at.isoformat(),
|
|
120
|
-
"title": "Cached repo",
|
|
121
|
-
"project_key": "CEP",
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if version:
|
|
125
|
-
entry["version"] = version
|
|
126
|
-
return entry
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def _make_metrics(**overrides: Any) -> CompletenessMetrics:
|
|
130
|
-
"""Create CompletenessMetrics for testing."""
|
|
131
|
-
now = datetime.now(UTC)
|
|
132
|
-
defaults = {
|
|
133
|
-
"total_required": 10,
|
|
134
|
-
"total_prepared": 8,
|
|
135
|
-
"total_missing": 2,
|
|
136
|
-
"total_stale": 1,
|
|
137
|
-
"total_aging": 2,
|
|
138
|
-
"completeness_pct": 80.0,
|
|
139
|
-
"freshness_pct": 62.5,
|
|
140
|
-
"avg_freshness_hours": 18.5,
|
|
141
|
-
"cache_hit_rate": 80.0,
|
|
142
|
-
"deep_checked": False,
|
|
143
|
-
"checked_at": now,
|
|
144
|
-
}
|
|
145
|
-
defaults.update(overrides)
|
|
146
|
-
return CompletenessMetrics(**defaults)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
# ===========================================================================
|
|
150
|
-
# Service Construction Tests
|
|
151
|
-
# ===========================================================================
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
class TestMaterialCompletenessServiceConstruction:
|
|
155
|
-
"""Tests for service construction and initialization (20 tests)."""
|
|
156
|
-
|
|
157
|
-
def test_default_initialization(self):
|
|
158
|
-
"""Service should initialize with required dependencies."""
|
|
159
|
-
state = _make_state_store()
|
|
160
|
-
cache = _make_cache()
|
|
161
|
-
|
|
162
|
-
service = MaterialCompletenessService(state, cache)
|
|
163
|
-
|
|
164
|
-
assert service.state is state
|
|
165
|
-
assert service.cache is cache
|
|
166
|
-
assert service.registry is None
|
|
167
|
-
assert service.config_path == MaterialCompletenessService.DEFAULT_CONFIG_PATH
|
|
168
|
-
|
|
169
|
-
def test_with_registry_parser(self):
|
|
170
|
-
"""Service should accept optional registry parser."""
|
|
171
|
-
state = _make_state_store()
|
|
172
|
-
cache = _make_cache()
|
|
173
|
-
registry = _make_registry_parser()
|
|
174
|
-
|
|
175
|
-
service = MaterialCompletenessService(state, cache, registry_parser=registry)
|
|
176
|
-
|
|
177
|
-
assert service.registry is registry
|
|
178
|
-
|
|
179
|
-
def test_with_custom_config_path(self, tmp_path: Path):
|
|
180
|
-
"""Service should accept custom config path."""
|
|
181
|
-
state = _make_state_store()
|
|
182
|
-
cache = _make_cache()
|
|
183
|
-
custom_path = tmp_path / "custom-config.yaml"
|
|
184
|
-
|
|
185
|
-
service = MaterialCompletenessService(state, cache, config_path=custom_path)
|
|
186
|
-
|
|
187
|
-
assert service.config_path == custom_path
|
|
188
|
-
|
|
189
|
-
def test_default_config_path_location(self):
|
|
190
|
-
"""Default config path should be ~/.vds/config/material-requirements.yaml."""
|
|
191
|
-
from pathlib import Path
|
|
192
|
-
|
|
193
|
-
expected = Path.home() / ".vds" / "config" / "material-requirements.yaml"
|
|
194
|
-
assert expected == MaterialCompletenessService.DEFAULT_CONFIG_PATH
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
# ===========================================================================
|
|
198
|
-
# Requirement Discovery Tests
|
|
199
|
-
# ===========================================================================
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
class TestDiscoverFromRegistry:
|
|
203
|
-
"""Tests for registry-based requirement discovery (15 tests)."""
|
|
204
|
-
|
|
205
|
-
@pytest.mark.asyncio
|
|
206
|
-
async def test_discover_from_registry_with_confluence_links(self):
|
|
207
|
-
"""Should extract page requirements from Confluence links."""
|
|
208
|
-
state = _make_state_store(
|
|
209
|
-
project_links=[
|
|
210
|
-
{
|
|
211
|
-
"link_type": "confluence",
|
|
212
|
-
"link_role": "page",
|
|
213
|
-
"normalized_url": "http://confluence/pages/88718940",
|
|
214
|
-
"title": "Test Page",
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
"link_type": "confluence",
|
|
218
|
-
"link_role": "attachment",
|
|
219
|
-
"normalized_url": "http://confluence/pages/88718941",
|
|
220
|
-
"title": "Test Attachment",
|
|
221
|
-
},
|
|
222
|
-
]
|
|
223
|
-
)
|
|
224
|
-
cache = _make_cache()
|
|
225
|
-
service = MaterialCompletenessService(state, cache)
|
|
226
|
-
|
|
227
|
-
requirements = await service._discover_from_registry("88718940")
|
|
228
|
-
|
|
229
|
-
assert len(requirements) == 2
|
|
230
|
-
assert requirements[0].material_type == MaterialType.page
|
|
231
|
-
assert requirements[0].identifier == "88718940"
|
|
232
|
-
assert requirements[0].source == "registry"
|
|
233
|
-
assert requirements[1].material_type == MaterialType.attachment
|
|
234
|
-
assert requirements[1].identifier == "88718941"
|
|
235
|
-
|
|
236
|
-
@pytest.mark.asyncio
|
|
237
|
-
async def test_discover_from_registry_extracts_page_id(self):
|
|
238
|
-
"""Should extract page_id from various URL formats."""
|
|
239
|
-
state = _make_state_store(
|
|
240
|
-
project_links=[
|
|
241
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://confluence/pages/12345"},
|
|
242
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://confluence?pageId=67890"},
|
|
243
|
-
]
|
|
244
|
-
)
|
|
245
|
-
cache = _make_cache()
|
|
246
|
-
service = MaterialCompletenessService(state, cache)
|
|
247
|
-
|
|
248
|
-
requirements = await service._discover_from_registry("88718940")
|
|
249
|
-
|
|
250
|
-
assert len(requirements) == 2
|
|
251
|
-
assert requirements[0].identifier == "12345"
|
|
252
|
-
assert requirements[1].identifier == "67890"
|
|
253
|
-
|
|
254
|
-
@pytest.mark.asyncio
|
|
255
|
-
async def test_discover_from_registry_skips_non_confluence(self):
|
|
256
|
-
"""Should skip non-Confluence links."""
|
|
257
|
-
state = _make_state_store(
|
|
258
|
-
project_links=[
|
|
259
|
-
{"link_type": "http", "link_role": "page", "normalized_url": "http://example.com"},
|
|
260
|
-
{"link_type": "bitbucket", "link_role": "repo", "normalized_url": "http://bitbucket/repo"},
|
|
261
|
-
]
|
|
262
|
-
)
|
|
263
|
-
cache = _make_cache()
|
|
264
|
-
service = MaterialCompletenessService(state, cache)
|
|
265
|
-
|
|
266
|
-
requirements = await service._discover_from_registry("88718940")
|
|
267
|
-
|
|
268
|
-
assert len(requirements) == 0
|
|
269
|
-
|
|
270
|
-
@pytest.mark.asyncio
|
|
271
|
-
async def test_discover_from_registry_bitbucket_role(self):
|
|
272
|
-
"""Should map bitbucket link_role to repo material type."""
|
|
273
|
-
state = _make_state_store(
|
|
274
|
-
project_links=[
|
|
275
|
-
{"link_type": "confluence", "link_role": "bitbucket", "normalized_url": "http://bitbucket/CEP/repo"},
|
|
276
|
-
{"link_type": "confluence", "link_role": "repository", "normalized_url": "http://bitbucket/CEP/repo2"},
|
|
277
|
-
]
|
|
278
|
-
)
|
|
279
|
-
cache = _make_cache()
|
|
280
|
-
service = MaterialCompletenessService(state, cache)
|
|
281
|
-
|
|
282
|
-
requirements = await service._discover_from_registry("88718940")
|
|
283
|
-
|
|
284
|
-
assert len(requirements) == 2
|
|
285
|
-
assert all(req.material_type == MaterialType.repo for req in requirements)
|
|
286
|
-
|
|
287
|
-
@pytest.mark.asyncio
|
|
288
|
-
async def test_discover_from_registry_captures_title(self):
|
|
289
|
-
"""Should capture link title in requirement."""
|
|
290
|
-
title = "Important Documentation Page"
|
|
291
|
-
state = _make_state_store(
|
|
292
|
-
project_links=[
|
|
293
|
-
{
|
|
294
|
-
"link_type": "confluence",
|
|
295
|
-
"link_role": "page",
|
|
296
|
-
"normalized_url": "http://confluence/pages/123",
|
|
297
|
-
"title": title,
|
|
298
|
-
},
|
|
299
|
-
]
|
|
300
|
-
)
|
|
301
|
-
cache = _make_cache()
|
|
302
|
-
service = MaterialCompletenessService(state, cache)
|
|
303
|
-
|
|
304
|
-
requirements = await service._discover_from_registry("88718940")
|
|
305
|
-
|
|
306
|
-
assert len(requirements) == 1
|
|
307
|
-
assert requirements[0].title == title
|
|
308
|
-
|
|
309
|
-
@pytest.mark.asyncio
|
|
310
|
-
async def test_discover_from_registry_empty_links(self):
|
|
311
|
-
"""Should return empty list when no links found."""
|
|
312
|
-
state = _make_state_store(project_links=[])
|
|
313
|
-
cache = _make_cache()
|
|
314
|
-
service = MaterialCompletenessService(state, cache)
|
|
315
|
-
|
|
316
|
-
requirements = await service._discover_from_registry("88718940")
|
|
317
|
-
|
|
318
|
-
assert requirements == []
|
|
319
|
-
|
|
320
|
-
@pytest.mark.asyncio
|
|
321
|
-
async def test_discover_from_registry_handles_link_without_page_id(self):
|
|
322
|
-
"""Should skip links that don't contain extractable page_id."""
|
|
323
|
-
state = _make_state_store(
|
|
324
|
-
project_links=[
|
|
325
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://confluence/invalid"},
|
|
326
|
-
]
|
|
327
|
-
)
|
|
328
|
-
cache = _make_cache()
|
|
329
|
-
service = MaterialCompletenessService(state, cache)
|
|
330
|
-
|
|
331
|
-
requirements = await service._discover_from_registry("88718940")
|
|
332
|
-
|
|
333
|
-
assert requirements == []
|
|
334
|
-
|
|
335
|
-
@pytest.mark.asyncio
|
|
336
|
-
async def test_discover_from_registry_sets_metadata(self):
|
|
337
|
-
"""Should include link metadata in requirement."""
|
|
338
|
-
state = _make_state_store(
|
|
339
|
-
project_links=[
|
|
340
|
-
{
|
|
341
|
-
"link_type": "confluence",
|
|
342
|
-
"link_role": "page",
|
|
343
|
-
"normalized_url": "http://c/p/123",
|
|
344
|
-
"raw_url": "http://original",
|
|
345
|
-
},
|
|
346
|
-
]
|
|
347
|
-
)
|
|
348
|
-
cache = _make_cache()
|
|
349
|
-
service = MaterialCompletenessService(state, cache)
|
|
350
|
-
|
|
351
|
-
requirements = await service._discover_from_registry("88718940")
|
|
352
|
-
|
|
353
|
-
assert len(requirements) == 1
|
|
354
|
-
assert requirements[0].metadata["link_role"] == "page"
|
|
355
|
-
assert requirements[0].metadata["raw_url"] == "http://original"
|
|
356
|
-
|
|
357
|
-
@pytest.mark.asyncio
|
|
358
|
-
async def test_discover_from_registry_default_priority(self):
|
|
359
|
-
"""Should set default priority for registry requirements."""
|
|
360
|
-
state = _make_state_store(
|
|
361
|
-
project_links=[
|
|
362
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/123"},
|
|
363
|
-
]
|
|
364
|
-
)
|
|
365
|
-
cache = _make_cache()
|
|
366
|
-
service = MaterialCompletenessService(state, cache)
|
|
367
|
-
|
|
368
|
-
requirements = await service._discover_from_registry("88718940")
|
|
369
|
-
|
|
370
|
-
assert requirements[0].priority == 10
|
|
371
|
-
|
|
372
|
-
@pytest.mark.asyncio
|
|
373
|
-
async def test_discover_from_registry_no_registry_parser(self):
|
|
374
|
-
"""Should return empty list when registry parser is None."""
|
|
375
|
-
state = _make_state_store()
|
|
376
|
-
cache = _make_cache()
|
|
377
|
-
service = MaterialCompletenessService(state, cache, registry_parser=None)
|
|
378
|
-
|
|
379
|
-
requirements = await service._discover_from_registry("88718940")
|
|
380
|
-
|
|
381
|
-
assert requirements == []
|
|
382
|
-
|
|
383
|
-
@pytest.mark.asyncio
|
|
384
|
-
async def test_discover_from_registry_handles_api_error_gracefully(self):
|
|
385
|
-
"""Should log warning and continue if state.get_project_links fails."""
|
|
386
|
-
state = _make_state_store()
|
|
387
|
-
state.get_project_links = AsyncMock(side_effect=Exception("API error"))
|
|
388
|
-
cache = _make_cache()
|
|
389
|
-
service = MaterialCompletenessService(state, cache)
|
|
390
|
-
|
|
391
|
-
requirements = await service._discover_from_registry("88718940")
|
|
392
|
-
|
|
393
|
-
assert requirements == []
|
|
394
|
-
|
|
395
|
-
@pytest.mark.asyncio
|
|
396
|
-
async def test_discover_from_registry_deduplicates_by_key(self):
|
|
397
|
-
"""Should deduplicate requirements with same key."""
|
|
398
|
-
state = _make_state_store(
|
|
399
|
-
project_links=[
|
|
400
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/123", "title": "First"},
|
|
401
|
-
{
|
|
402
|
-
"link_type": "confluence",
|
|
403
|
-
"link_role": "page",
|
|
404
|
-
"normalized_url": "http://c/p/123",
|
|
405
|
-
"title": "Duplicate",
|
|
406
|
-
},
|
|
407
|
-
]
|
|
408
|
-
)
|
|
409
|
-
cache = _make_cache()
|
|
410
|
-
service = MaterialCompletenessService(state, cache)
|
|
411
|
-
|
|
412
|
-
requirements = await service._discover_from_registry("88718940")
|
|
413
|
-
|
|
414
|
-
assert len(requirements) == 1
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
class TestDiscoverFromChecklist:
|
|
418
|
-
"""Tests for checklist-based requirement discovery (15 tests)."""
|
|
419
|
-
|
|
420
|
-
@pytest.mark.asyncio
|
|
421
|
-
async def test_discover_from_checklist_with_pages(self):
|
|
422
|
-
"""Should extract page requirements from artifacts."""
|
|
423
|
-
state = _make_state_store(
|
|
424
|
-
project_preparation={
|
|
425
|
-
"sync_metadata": {
|
|
426
|
-
"artifacts": [
|
|
427
|
-
{"page_id": "88718940", "type": "page", "title": "Page 1"},
|
|
428
|
-
{"page_id": "88718941", "type": "page", "title": "Page 2"},
|
|
429
|
-
]
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
)
|
|
433
|
-
cache = _make_cache()
|
|
434
|
-
service = MaterialCompletenessService(state, cache)
|
|
435
|
-
|
|
436
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
437
|
-
|
|
438
|
-
assert len(requirements) == 2
|
|
439
|
-
assert all(req.material_type == MaterialType.page for req in requirements)
|
|
440
|
-
assert all(req.source == "checklist" for req in requirements)
|
|
441
|
-
|
|
442
|
-
@pytest.mark.asyncio
|
|
443
|
-
async def test_discover_from_checklist_with_attachments(self):
|
|
444
|
-
"""Should extract attachment requirements from artifacts."""
|
|
445
|
-
state = _make_state_store(
|
|
446
|
-
project_preparation={
|
|
447
|
-
"sync_metadata": {
|
|
448
|
-
"artifacts": [
|
|
449
|
-
{"page_id": "88718940", "attachment_id": "att1", "type": "attachment", "title": "File1.pdf"},
|
|
450
|
-
{"page_id": "88718940", "attachment_id": "att2", "type": "attachment", "title": "File2.pdf"},
|
|
451
|
-
]
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
)
|
|
455
|
-
cache = _make_cache()
|
|
456
|
-
service = MaterialCompletenessService(state, cache)
|
|
457
|
-
|
|
458
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
459
|
-
|
|
460
|
-
assert len(requirements) == 2
|
|
461
|
-
assert all(req.material_type == MaterialType.attachment for req in requirements)
|
|
462
|
-
assert requirements[0].identifier == "att1"
|
|
463
|
-
assert requirements[1].identifier == "att2"
|
|
464
|
-
|
|
465
|
-
@pytest.mark.asyncio
|
|
466
|
-
async def test_discover_from_checklist_with_repos(self):
|
|
467
|
-
"""Should extract repo requirements from artifacts."""
|
|
468
|
-
state = _make_state_store(
|
|
469
|
-
project_preparation={
|
|
470
|
-
"sync_metadata": {
|
|
471
|
-
"artifacts": [
|
|
472
|
-
{"page_id": "88718940", "repo_key": "merchant-report", "type": "repo"},
|
|
473
|
-
{"page_id": "88718941", "repo_key": "merchant-billing", "type": "bitbucket"},
|
|
474
|
-
]
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
)
|
|
478
|
-
cache = _make_cache()
|
|
479
|
-
service = MaterialCompletenessService(state, cache)
|
|
480
|
-
|
|
481
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
482
|
-
|
|
483
|
-
assert len(requirements) == 2
|
|
484
|
-
assert all(req.material_type == MaterialType.repo for req in requirements)
|
|
485
|
-
assert requirements[0].identifier == "merchant-report"
|
|
486
|
-
assert requirements[1].identifier == "merchant-billing"
|
|
487
|
-
|
|
488
|
-
@pytest.mark.asyncio
|
|
489
|
-
async def test_discover_from_checklist_empty_preparation(self):
|
|
490
|
-
"""Should return empty list when no preparation data."""
|
|
491
|
-
state = _make_state_store(project_preparation=None)
|
|
492
|
-
cache = _make_cache()
|
|
493
|
-
service = MaterialCompletenessService(state, cache)
|
|
494
|
-
|
|
495
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
496
|
-
|
|
497
|
-
assert requirements == []
|
|
498
|
-
|
|
499
|
-
@pytest.mark.asyncio
|
|
500
|
-
async def test_discover_from_checklist_no_sync_metadata(self):
|
|
501
|
-
"""Should return empty list when sync_metadata missing."""
|
|
502
|
-
state = _make_state_store(project_preparation={})
|
|
503
|
-
cache = _make_cache()
|
|
504
|
-
service = MaterialCompletenessService(state, cache)
|
|
505
|
-
|
|
506
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
507
|
-
|
|
508
|
-
assert requirements == []
|
|
509
|
-
|
|
510
|
-
@pytest.mark.asyncio
|
|
511
|
-
async def test_discover_from_checklist_no_artifacts(self):
|
|
512
|
-
"""Should return empty list when artifacts list empty."""
|
|
513
|
-
state = _make_state_store(project_preparation={"sync_metadata": {"artifacts": []}})
|
|
514
|
-
cache = _make_cache()
|
|
515
|
-
service = MaterialCompletenessService(state, cache)
|
|
516
|
-
|
|
517
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
518
|
-
|
|
519
|
-
assert requirements == []
|
|
520
|
-
|
|
521
|
-
@pytest.mark.asyncio
|
|
522
|
-
async def test_discover_from_checklist_mixed_types(self):
|
|
523
|
-
"""Should handle mixed page/attachment/repo artifacts."""
|
|
524
|
-
state = _make_state_store(
|
|
525
|
-
project_preparation={
|
|
526
|
-
"sync_metadata": {
|
|
527
|
-
"artifacts": [
|
|
528
|
-
{"page_id": "88718940", "type": "page"},
|
|
529
|
-
{"page_id": "88718940", "attachment_id": "att1", "type": "attachment"},
|
|
530
|
-
{"page_id": "88718940", "repo_key": "repo1", "type": "repo"},
|
|
531
|
-
]
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
)
|
|
535
|
-
cache = _make_cache()
|
|
536
|
-
service = MaterialCompletenessService(state, cache)
|
|
537
|
-
|
|
538
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
539
|
-
|
|
540
|
-
assert len(requirements) == 3
|
|
541
|
-
assert requirements[0].material_type == MaterialType.page
|
|
542
|
-
assert requirements[1].material_type == MaterialType.attachment
|
|
543
|
-
assert requirements[2].material_type == MaterialType.repo
|
|
544
|
-
|
|
545
|
-
@pytest.mark.asyncio
|
|
546
|
-
async def test_discover_from_checklist_attachment_uses_page_id(self):
|
|
547
|
-
"""Should use page_id for attachment when attachment_id missing."""
|
|
548
|
-
state = _make_state_store(
|
|
549
|
-
project_preparation={
|
|
550
|
-
"sync_metadata": {
|
|
551
|
-
"artifacts": [
|
|
552
|
-
{"page_id": "88718940", "type": "attachment"},
|
|
553
|
-
]
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
)
|
|
557
|
-
cache = _make_cache()
|
|
558
|
-
service = MaterialCompletenessService(state, cache)
|
|
559
|
-
|
|
560
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
561
|
-
|
|
562
|
-
assert len(requirements) == 1
|
|
563
|
-
assert requirements[0].material_type == MaterialType.attachment
|
|
564
|
-
assert requirements[0].identifier == "88718940"
|
|
565
|
-
|
|
566
|
-
@pytest.mark.asyncio
|
|
567
|
-
async def test_discover_from_checklist_captures_title(self):
|
|
568
|
-
"""Should capture artifact title in requirement."""
|
|
569
|
-
title = "Important Document"
|
|
570
|
-
state = _make_state_store(
|
|
571
|
-
project_preparation={
|
|
572
|
-
"sync_metadata": {
|
|
573
|
-
"artifacts": [
|
|
574
|
-
{"page_id": "88718940", "type": "page", "title": title},
|
|
575
|
-
]
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
)
|
|
579
|
-
cache = _make_cache()
|
|
580
|
-
service = MaterialCompletenessService(state, cache)
|
|
581
|
-
|
|
582
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
583
|
-
|
|
584
|
-
assert len(requirements) == 1
|
|
585
|
-
assert requirements[0].title == title
|
|
586
|
-
|
|
587
|
-
@pytest.mark.asyncio
|
|
588
|
-
async def test_discover_from_checklist_default_priority(self):
|
|
589
|
-
"""Should set default priority for checklist requirements."""
|
|
590
|
-
state = _make_state_store(
|
|
591
|
-
project_preparation={
|
|
592
|
-
"sync_metadata": {
|
|
593
|
-
"artifacts": [
|
|
594
|
-
{"page_id": "88718940", "type": "page"},
|
|
595
|
-
]
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
)
|
|
599
|
-
cache = _make_cache()
|
|
600
|
-
service = MaterialCompletenessService(state, cache)
|
|
601
|
-
|
|
602
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
603
|
-
|
|
604
|
-
assert requirements[0].priority == 20
|
|
605
|
-
|
|
606
|
-
@pytest.mark.asyncio
|
|
607
|
-
async def test_discover_from_checklist_includes_artifact_type(self):
|
|
608
|
-
"""Should include artifact type in metadata."""
|
|
609
|
-
state = _make_state_store(
|
|
610
|
-
project_preparation={
|
|
611
|
-
"sync_metadata": {
|
|
612
|
-
"artifacts": [
|
|
613
|
-
{"page_id": "88718940", "type": "custom_type", "title": "Custom"},
|
|
614
|
-
]
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
)
|
|
618
|
-
cache = _make_cache()
|
|
619
|
-
service = MaterialCompletenessService(state, cache)
|
|
620
|
-
|
|
621
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
622
|
-
|
|
623
|
-
assert len(requirements) == 1
|
|
624
|
-
assert requirements[0].metadata["artifact_type"] == "custom_type"
|
|
625
|
-
|
|
626
|
-
@pytest.mark.asyncio
|
|
627
|
-
async def test_discover_from_checklist_handles_invalid_artifacts(self):
|
|
628
|
-
"""Should skip invalid artifact entries."""
|
|
629
|
-
state = _make_state_store(
|
|
630
|
-
project_preparation={
|
|
631
|
-
"sync_metadata": {
|
|
632
|
-
"artifacts": [
|
|
633
|
-
"not_a_dict",
|
|
634
|
-
{"page_id": "88718940", "type": "page"}, # valid
|
|
635
|
-
None,
|
|
636
|
-
]
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
)
|
|
640
|
-
cache = _make_cache()
|
|
641
|
-
service = MaterialCompletenessService(state, cache)
|
|
642
|
-
|
|
643
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
644
|
-
|
|
645
|
-
assert len(requirements) == 1
|
|
646
|
-
|
|
647
|
-
@pytest.mark.asyncio
|
|
648
|
-
async def test_discover_from_checklist_handles_api_error(self):
|
|
649
|
-
"""Should log warning and continue if state.get_project_preparation fails."""
|
|
650
|
-
state = _make_state_store()
|
|
651
|
-
state.get_project_preparation = AsyncMock(side_effect=Exception("DB error"))
|
|
652
|
-
cache = _make_cache()
|
|
653
|
-
service = MaterialCompletenessService(state, cache)
|
|
654
|
-
|
|
655
|
-
requirements = await service._discover_from_checklist("88718940")
|
|
656
|
-
|
|
657
|
-
assert requirements == []
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
class TestLoadConfigRequirements:
|
|
661
|
-
"""Tests for config file requirement loading (15 tests)."""
|
|
662
|
-
|
|
663
|
-
def test_load_config_from_nonexistent_file(self):
|
|
664
|
-
"""Should return empty list when config file doesn't exist."""
|
|
665
|
-
state = _make_state_store()
|
|
666
|
-
cache = _make_cache()
|
|
667
|
-
service = MaterialCompletenessService(state, cache, config_path=Path("/nonexistent/config.yaml"))
|
|
668
|
-
|
|
669
|
-
requirements = service._load_config_requirements("88718940")
|
|
670
|
-
|
|
671
|
-
assert requirements == []
|
|
672
|
-
|
|
673
|
-
def test_load_config_global_requirements(self, tmp_path: Path):
|
|
674
|
-
"""Should load global requirements from config file."""
|
|
675
|
-
config_path = tmp_path / "material-requirements.yaml"
|
|
676
|
-
config_path.write_text(
|
|
677
|
-
"""
|
|
678
|
-
requirements:
|
|
679
|
-
- material_type: page
|
|
680
|
-
identifier: "88718940"
|
|
681
|
-
project_key: "CEP"
|
|
682
|
-
priority: 100
|
|
683
|
-
- material_type: repo
|
|
684
|
-
identifier: "merchant-report"
|
|
685
|
-
project_key: "PAR"
|
|
686
|
-
priority: 100
|
|
687
|
-
""",
|
|
688
|
-
encoding="utf-8",
|
|
689
|
-
)
|
|
690
|
-
|
|
691
|
-
state = _make_state_store()
|
|
692
|
-
cache = _make_cache()
|
|
693
|
-
service = MaterialCompletenessService(state, cache, config_path=config_path)
|
|
694
|
-
|
|
695
|
-
requirements = service._load_config_requirements("88718940")
|
|
696
|
-
|
|
697
|
-
assert len(requirements) == 2
|
|
698
|
-
assert requirements[0].material_type == MaterialType.page
|
|
699
|
-
assert requirements[0].priority == 100
|
|
700
|
-
assert requirements[1].material_type == MaterialType.repo
|
|
701
|
-
|
|
702
|
-
def test_load_config_project_specific_overrides(self, tmp_path: Path):
|
|
703
|
-
"""Should load project-specific requirements and override global."""
|
|
704
|
-
config_path = tmp_path / "material-requirements.yaml"
|
|
705
|
-
config_path.write_text(
|
|
706
|
-
"""
|
|
707
|
-
requirements:
|
|
708
|
-
- material_type: page
|
|
709
|
-
identifier: "global-page"
|
|
710
|
-
project_key: "global"
|
|
711
|
-
priority: 50
|
|
712
|
-
projects:
|
|
713
|
-
88718940:
|
|
714
|
-
requirements:
|
|
715
|
-
- material_type: page
|
|
716
|
-
identifier: "local-page"
|
|
717
|
-
project_key: "88718940"
|
|
718
|
-
priority: 150
|
|
719
|
-
""",
|
|
720
|
-
encoding="utf-8",
|
|
721
|
-
)
|
|
722
|
-
|
|
723
|
-
state = _make_state_store()
|
|
724
|
-
cache = _make_cache()
|
|
725
|
-
service = MaterialCompletenessService(state, cache, config_path=config_path)
|
|
726
|
-
|
|
727
|
-
requirements = service._load_config_requirements("88718940")
|
|
728
|
-
|
|
729
|
-
# Should have both global and project-specific
|
|
730
|
-
assert len(requirements) == 2
|
|
731
|
-
# Project-specific has higher priority
|
|
732
|
-
local_req = next(r for r in requirements if r.identifier == "local-page")
|
|
733
|
-
assert local_req.priority == 150
|
|
734
|
-
|
|
735
|
-
def test_load_config_resolves_project_key_in_overrides(self, tmp_path: Path):
|
|
736
|
-
"""Should use provided project_key for global requirements."""
|
|
737
|
-
config_path = tmp_path / "material-requirements.yaml"
|
|
738
|
-
config_path.write_text(
|
|
739
|
-
"""
|
|
740
|
-
requirements:
|
|
741
|
-
- material_type: page
|
|
742
|
-
identifier: "88718940"
|
|
743
|
-
priority: 100
|
|
744
|
-
""",
|
|
745
|
-
encoding="utf-8",
|
|
746
|
-
)
|
|
747
|
-
|
|
748
|
-
state = _make_state_store()
|
|
749
|
-
cache = _make_cache()
|
|
750
|
-
service = MaterialCompletenessService(state, cache, config_path=config_path)
|
|
751
|
-
|
|
752
|
-
requirements = service._load_config_requirements("CEP")
|
|
753
|
-
|
|
754
|
-
# Config requirement should inherit project_key from parameter
|
|
755
|
-
assert len(requirements) == 1
|
|
756
|
-
assert requirements[0].project_key == "CEP"
|
|
757
|
-
|
|
758
|
-
def test_load_config_with_invalid_material_type(self, tmp_path: Path):
|
|
759
|
-
"""Should skip requirements with invalid material_type."""
|
|
760
|
-
config_path = tmp_path / "material-requirements.yaml"
|
|
761
|
-
config_path.write_text(
|
|
762
|
-
"""
|
|
763
|
-
requirements:
|
|
764
|
-
- material_type: invalid_type
|
|
765
|
-
identifier: "88718940"
|
|
766
|
-
""",
|
|
767
|
-
encoding="utf-8",
|
|
768
|
-
)
|
|
769
|
-
|
|
770
|
-
state = _make_state_store()
|
|
771
|
-
cache = _make_cache()
|
|
772
|
-
service = MaterialCompletenessService(state, cache, config_path=config_path)
|
|
773
|
-
|
|
774
|
-
requirements = service._load_config_requirements("88718940")
|
|
775
|
-
|
|
776
|
-
assert requirements == []
|
|
777
|
-
|
|
778
|
-
def test_load_config_with_all_optional_fields(self, tmp_path: Path):
|
|
779
|
-
"""Should parse all optional fields correctly."""
|
|
780
|
-
config_path = tmp_path / "material-requirements.yaml"
|
|
781
|
-
config_path.write_text(
|
|
782
|
-
"""
|
|
783
|
-
requirements:
|
|
784
|
-
- material_type: attachment
|
|
785
|
-
identifier: "att123"
|
|
786
|
-
project_key: "CEP"
|
|
787
|
-
priority: 200
|
|
788
|
-
title: "Important File"
|
|
789
|
-
metadata:
|
|
790
|
-
custom_field: value
|
|
791
|
-
""",
|
|
792
|
-
encoding="utf-8",
|
|
793
|
-
)
|
|
794
|
-
|
|
795
|
-
state = _make_state_store()
|
|
796
|
-
cache = _make_cache()
|
|
797
|
-
service = MaterialCompletenessService(state, cache, config_path=config_path)
|
|
798
|
-
|
|
799
|
-
requirements = service._load_config_requirements("CEP")
|
|
800
|
-
|
|
801
|
-
assert len(requirements) == 1
|
|
802
|
-
req = requirements[0]
|
|
803
|
-
assert req.material_type == MaterialType.attachment
|
|
804
|
-
assert req.identifier == "att123"
|
|
805
|
-
assert req.priority == 200
|
|
806
|
-
assert req.title == "Important File"
|
|
807
|
-
assert req.metadata["custom_field"] == "value"
|
|
808
|
-
|
|
809
|
-
def test_load_config_handles_invalid_yaml(self, tmp_path: Path):
|
|
810
|
-
"""Should return empty list for invalid YAML."""
|
|
811
|
-
config_path = tmp_path / "material-requirements.yaml"
|
|
812
|
-
config_path.write_text("invalid: yaml: content: [", encoding="utf-8")
|
|
813
|
-
|
|
814
|
-
state = _make_state_store()
|
|
815
|
-
cache = _make_cache()
|
|
816
|
-
service = MaterialCompletenessService(state, cache, config_path=config_path)
|
|
817
|
-
|
|
818
|
-
requirements = service._load_config_requirements("CEP")
|
|
819
|
-
|
|
820
|
-
assert requirements == []
|
|
821
|
-
|
|
822
|
-
def test_load_config_handles_non_dict_root(self, tmp_path: Path):
|
|
823
|
-
"""Should return empty list when root is not a dict."""
|
|
824
|
-
config_path = tmp_path / "material-requirements.yaml"
|
|
825
|
-
config_path.write_text("just a string", encoding="utf-8")
|
|
826
|
-
|
|
827
|
-
state = _make_state_store()
|
|
828
|
-
cache = _make_cache()
|
|
829
|
-
service = MaterialCompletenessService(state, cache, config_path=config_path)
|
|
830
|
-
|
|
831
|
-
requirements = service._load_config_requirements("CEP")
|
|
832
|
-
|
|
833
|
-
assert requirements == []
|
|
834
|
-
|
|
835
|
-
def test_load_config_handles_empty_requirements_list(self, tmp_path: Path):
|
|
836
|
-
"""Should handle empty requirements list."""
|
|
837
|
-
config_path = tmp_path / "material-requirements.yaml"
|
|
838
|
-
config_path.write_text("requirements: []", encoding="utf-8")
|
|
839
|
-
|
|
840
|
-
state = _make_state_store()
|
|
841
|
-
cache = _make_cache()
|
|
842
|
-
service = MaterialCompletenessService(state, cache, config_path=config_path)
|
|
843
|
-
|
|
844
|
-
requirements = service._load_config_requirements("CEP")
|
|
845
|
-
|
|
846
|
-
assert requirements == []
|
|
847
|
-
|
|
848
|
-
def test_parse_requirement_dict_with_valid_data(self):
|
|
849
|
-
"""Should parse valid requirement dict correctly."""
|
|
850
|
-
state = _make_state_store()
|
|
851
|
-
cache = _make_cache()
|
|
852
|
-
service = MaterialCompletenessService(state, cache)
|
|
853
|
-
|
|
854
|
-
data = {
|
|
855
|
-
"material_type": "page",
|
|
856
|
-
"identifier": "88718940",
|
|
857
|
-
"project_key": "CEP",
|
|
858
|
-
"source": "explicit",
|
|
859
|
-
"priority": 100,
|
|
860
|
-
"title": "Test",
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
req = service._parse_requirement_dict(data, "88718940")
|
|
864
|
-
|
|
865
|
-
assert req.material_type == MaterialType.page
|
|
866
|
-
assert req.identifier == "88718940"
|
|
867
|
-
assert req.project_key == "CEP"
|
|
868
|
-
# Source is taken from data dict if provided
|
|
869
|
-
assert req.source == "explicit"
|
|
870
|
-
assert req.priority == 100
|
|
871
|
-
assert req.title == "Test"
|
|
872
|
-
|
|
873
|
-
def test_parse_requirement_dict_with_defaults(self):
|
|
874
|
-
"""Should use defaults for optional fields."""
|
|
875
|
-
state = _make_state_store()
|
|
876
|
-
cache = _make_cache()
|
|
877
|
-
service = MaterialCompletenessService(state, cache)
|
|
878
|
-
|
|
879
|
-
data = {"material_type": "page", "identifier": "88718940"}
|
|
880
|
-
|
|
881
|
-
req = service._parse_requirement_dict(data, "CEP")
|
|
882
|
-
|
|
883
|
-
assert req.material_type == MaterialType.page
|
|
884
|
-
assert req.identifier == "88718940"
|
|
885
|
-
assert req.project_key == "CEP"
|
|
886
|
-
# Source defaults to "config" when parsing from config file
|
|
887
|
-
assert req.source == "config"
|
|
888
|
-
assert req.priority == 100 # default
|
|
889
|
-
assert req.title is None
|
|
890
|
-
assert req.metadata == {}
|
|
891
|
-
|
|
892
|
-
def test_parse_requirement_dict_invalid_material_type(self):
|
|
893
|
-
"""Should return None for invalid material type."""
|
|
894
|
-
state = _make_state_store()
|
|
895
|
-
cache = _make_cache()
|
|
896
|
-
service = MaterialCompletenessService(state, cache)
|
|
897
|
-
|
|
898
|
-
data = {"material_type": "invalid", "identifier": "88718940"}
|
|
899
|
-
|
|
900
|
-
req = service._parse_requirement_dict(data, "CEP")
|
|
901
|
-
|
|
902
|
-
assert req is None
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
class TestDiscoverRequirements:
|
|
906
|
-
"""Tests for multi-source requirement discovery and merging (15 tests)."""
|
|
907
|
-
|
|
908
|
-
@pytest.mark.asyncio
|
|
909
|
-
async def test_discover_requirements_merges_all_sources(self):
|
|
910
|
-
"""Should merge requirements from all available sources."""
|
|
911
|
-
state = _make_state_store(
|
|
912
|
-
project_links=[
|
|
913
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/111"},
|
|
914
|
-
],
|
|
915
|
-
project_preparation={"sync_metadata": {"artifacts": [{"page_id": "222", "type": "page"}]}},
|
|
916
|
-
)
|
|
917
|
-
cache = _make_cache()
|
|
918
|
-
service = MaterialCompletenessService(state, cache)
|
|
919
|
-
|
|
920
|
-
requirements = await service._discover_requirements("88718940")
|
|
921
|
-
|
|
922
|
-
assert len(requirements) >= 2
|
|
923
|
-
identifiers = {r.identifier for r in requirements}
|
|
924
|
-
assert "111" in identifiers # registry
|
|
925
|
-
assert "222" in identifiers # checklist
|
|
926
|
-
|
|
927
|
-
@pytest.mark.asyncio
|
|
928
|
-
async def test_discover_requirements_priority_deduplication(self):
|
|
929
|
-
"""Higher priority requirement should replace lower priority."""
|
|
930
|
-
state = _make_state_store(
|
|
931
|
-
project_links=[
|
|
932
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/123"},
|
|
933
|
-
],
|
|
934
|
-
project_preparation={"sync_metadata": {"artifacts": [{"page_id": "123", "type": "page"}]}},
|
|
935
|
-
)
|
|
936
|
-
cache = _make_cache()
|
|
937
|
-
|
|
938
|
-
# Explicit with priority 200 should win
|
|
939
|
-
explicit = [_make_requirement(identifier="123", source="explicit", priority=200)]
|
|
940
|
-
service = MaterialCompletenessService(state, cache)
|
|
941
|
-
service.config_path = Path("/nonexistent") # No config file
|
|
942
|
-
|
|
943
|
-
requirements = await service._discover_requirements("88718940", explicit_requirements=explicit)
|
|
944
|
-
|
|
945
|
-
# Should have only one requirement with highest priority
|
|
946
|
-
matching = [r for r in requirements if r.identifier == "123"]
|
|
947
|
-
assert len(matching) == 1
|
|
948
|
-
assert matching[0].source == "explicit"
|
|
949
|
-
assert matching[0].priority == 200
|
|
950
|
-
|
|
951
|
-
@pytest.mark.asyncio
|
|
952
|
-
async def test_discover_requirements_config_overrides_all(self, tmp_path: Path):
|
|
953
|
-
"""Config file requirements should override all others with priority 100."""
|
|
954
|
-
state = _make_state_store(
|
|
955
|
-
project_links=[
|
|
956
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/123"},
|
|
957
|
-
],
|
|
958
|
-
project_preparation={"sync_metadata": {"artifacts": [{"page_id": "123", "type": "page"}]}},
|
|
959
|
-
)
|
|
960
|
-
cache = _make_cache()
|
|
961
|
-
|
|
962
|
-
# Create a config file with priority 100 requirement
|
|
963
|
-
config_path = tmp_path / "material-requirements.yaml"
|
|
964
|
-
config_path.write_text(
|
|
965
|
-
"""
|
|
966
|
-
requirements:
|
|
967
|
-
- material_type: page
|
|
968
|
-
identifier: "123"
|
|
969
|
-
priority: 100
|
|
970
|
-
""",
|
|
971
|
-
encoding="utf-8",
|
|
972
|
-
)
|
|
973
|
-
|
|
974
|
-
# Config file sets priority to 100
|
|
975
|
-
explicit = [_make_requirement(identifier="123", source="explicit", priority=50)]
|
|
976
|
-
service = MaterialCompletenessService(state, cache, config_path=config_path)
|
|
977
|
-
|
|
978
|
-
requirements = await service._discover_requirements("88718940", explicit_requirements=explicit)
|
|
979
|
-
|
|
980
|
-
matching = [r for r in requirements if r.identifier == "123"]
|
|
981
|
-
assert len(matching) == 1
|
|
982
|
-
assert matching[0].priority == 100
|
|
983
|
-
|
|
984
|
-
@pytest.mark.asyncio
|
|
985
|
-
async def test_discover_requirements_explicit_highest_priority(self):
|
|
986
|
-
"""Explicit parameter requirements should have priority 200 (highest)."""
|
|
987
|
-
state = _make_state_store()
|
|
988
|
-
cache = _make_cache()
|
|
989
|
-
|
|
990
|
-
explicit = [_make_requirement(priority=200)]
|
|
991
|
-
service = MaterialCompletenessService(state, cache)
|
|
992
|
-
|
|
993
|
-
requirements = await service._discover_requirements("88718940", explicit_requirements=explicit)
|
|
994
|
-
|
|
995
|
-
assert requirements[0].priority == 200
|
|
996
|
-
|
|
997
|
-
@pytest.mark.asyncio
|
|
998
|
-
async def test_discover_requirements_empty_all_sources(self):
|
|
999
|
-
"""Should return empty list when all sources are empty."""
|
|
1000
|
-
state = _make_state_store()
|
|
1001
|
-
cache = _make_cache()
|
|
1002
|
-
service = MaterialCompletenessService(state, cache, registry_parser=None)
|
|
1003
|
-
|
|
1004
|
-
requirements = await service._discover_requirements("88718940")
|
|
1005
|
-
|
|
1006
|
-
assert requirements == []
|
|
1007
|
-
|
|
1008
|
-
@pytest.mark.asyncio
|
|
1009
|
-
async def test_discover_requirements_maintains_source_tracking(self):
|
|
1010
|
-
"""Should preserve source information in requirements."""
|
|
1011
|
-
state = _make_state_store(
|
|
1012
|
-
project_links=[
|
|
1013
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/111"},
|
|
1014
|
-
],
|
|
1015
|
-
project_preparation={"sync_metadata": {"artifacts": [{"page_id": "222", "type": "page"}]}},
|
|
1016
|
-
)
|
|
1017
|
-
cache = _make_cache()
|
|
1018
|
-
service = MaterialCompletenessService(state, cache)
|
|
1019
|
-
|
|
1020
|
-
requirements = await service._discover_requirements("88718940")
|
|
1021
|
-
|
|
1022
|
-
sources = {r.source for r in requirements}
|
|
1023
|
-
assert "registry" in sources
|
|
1024
|
-
assert "checklist" in sources
|
|
1025
|
-
|
|
1026
|
-
@pytest.mark.asyncio
|
|
1027
|
-
async def test_discover_requirements_handles_duplicate_identifiers(self):
|
|
1028
|
-
"""Should deduplicate requirements with same material_type:project_key:identifier."""
|
|
1029
|
-
state = _make_state_store(
|
|
1030
|
-
project_links=[
|
|
1031
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/123"},
|
|
1032
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/123"},
|
|
1033
|
-
],
|
|
1034
|
-
)
|
|
1035
|
-
cache = _make_cache()
|
|
1036
|
-
service = MaterialCompletenessService(state, cache)
|
|
1037
|
-
|
|
1038
|
-
requirements = await service._discover_requirements("88718940")
|
|
1039
|
-
|
|
1040
|
-
matching = [r for r in requirements if r.identifier == "123"]
|
|
1041
|
-
assert len(matching) == 1
|
|
1042
|
-
|
|
1043
|
-
@pytest.mark.asyncio
|
|
1044
|
-
async def test_discover_requirements_different_types_not_deduped(self):
|
|
1045
|
-
"""Should NOT deduplicate different material types with same identifier."""
|
|
1046
|
-
state = _make_state_store(
|
|
1047
|
-
project_links=[
|
|
1048
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/123"},
|
|
1049
|
-
],
|
|
1050
|
-
project_preparation={"sync_metadata": {"artifacts": [{"page_id": "123", "type": "attachment"}]}},
|
|
1051
|
-
)
|
|
1052
|
-
cache = _make_cache()
|
|
1053
|
-
service = MaterialCompletenessService(state, cache)
|
|
1054
|
-
|
|
1055
|
-
requirements = await service._discover_requirements("88718940")
|
|
1056
|
-
|
|
1057
|
-
# Should have both page and attachment with identifier "123"
|
|
1058
|
-
assert len(requirements) == 2
|
|
1059
|
-
|
|
1060
|
-
@pytest.mark.asyncio
|
|
1061
|
-
async def test_discover_requirements_respects_project_key(self):
|
|
1062
|
-
"""Should associate requirements with correct project key."""
|
|
1063
|
-
state = _make_state_store(
|
|
1064
|
-
project_links=[
|
|
1065
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/111"},
|
|
1066
|
-
],
|
|
1067
|
-
)
|
|
1068
|
-
cache = _make_cache()
|
|
1069
|
-
service = MaterialCompletenessService(state, cache)
|
|
1070
|
-
|
|
1071
|
-
requirements = await service._discover_requirements("88718940")
|
|
1072
|
-
|
|
1073
|
-
assert all(req.project_key == "88718940" for req in requirements)
|
|
1074
|
-
|
|
1075
|
-
@pytest.mark.asyncio
|
|
1076
|
-
async def test_discover_requirements_preserves_metadata(self):
|
|
1077
|
-
"""Should preserve metadata from original requirements."""
|
|
1078
|
-
state = _make_state_store(
|
|
1079
|
-
project_links=[
|
|
1080
|
-
{
|
|
1081
|
-
"link_type": "confluence",
|
|
1082
|
-
"link_role": "page",
|
|
1083
|
-
"normalized_url": "http://c/p/111",
|
|
1084
|
-
"title": "Custom Page",
|
|
1085
|
-
},
|
|
1086
|
-
],
|
|
1087
|
-
)
|
|
1088
|
-
cache = _make_cache()
|
|
1089
|
-
service = MaterialCompletenessService(state, cache)
|
|
1090
|
-
|
|
1091
|
-
requirements = await service._discover_requirements("88718940")
|
|
1092
|
-
|
|
1093
|
-
req = next(r for r in requirements if r.identifier == "111")
|
|
1094
|
-
assert req.title == "Custom Page"
|
|
1095
|
-
assert "link_role" in req.metadata
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
# ===========================================================================
|
|
1099
|
-
# Cache Validation Tests
|
|
1100
|
-
# ===========================================================================
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
class TestValidatePageRequirement:
|
|
1104
|
-
"""Tests for page requirement cache validation (20 tests)."""
|
|
1105
|
-
|
|
1106
|
-
@pytest.mark.asyncio
|
|
1107
|
-
async def test_validate_page_cached_fresh(self):
|
|
1108
|
-
"""Should return prepared for fresh cached page."""
|
|
1109
|
-
state = _make_state_store()
|
|
1110
|
-
cache = _make_cache()
|
|
1111
|
-
service = MaterialCompletenessService(state, cache)
|
|
1112
|
-
|
|
1113
|
-
req = _make_requirement(material_type=MaterialType.page, identifier="88718940")
|
|
1114
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
1115
|
-
|
|
1116
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
1117
|
-
result = await service._validate_page_requirement(req, deep_check=False)
|
|
1118
|
-
|
|
1119
|
-
assert result["status"] == "prepared"
|
|
1120
|
-
assert isinstance(result["entry"], PreparedMaterial)
|
|
1121
|
-
assert result["entry"].freshness == FreshnessTier.fresh
|
|
1122
|
-
assert result["entry"].age_hours == pytest.approx(2.0, rel=0.01)
|
|
1123
|
-
|
|
1124
|
-
@pytest.mark.asyncio
|
|
1125
|
-
async def test_validate_page_cached_aging(self):
|
|
1126
|
-
"""Should return prepared with aging tier for older page."""
|
|
1127
|
-
state = _make_state_store()
|
|
1128
|
-
cache = _make_cache()
|
|
1129
|
-
service = MaterialCompletenessService(state, cache)
|
|
1130
|
-
|
|
1131
|
-
req = _make_requirement(material_type=MaterialType.page, identifier="88718940")
|
|
1132
|
-
entry = _make_cache_entry(age_hours=30.0)
|
|
1133
|
-
|
|
1134
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
1135
|
-
result = await service._validate_page_requirement(req, deep_check=False)
|
|
1136
|
-
|
|
1137
|
-
assert result["status"] == "prepared"
|
|
1138
|
-
assert result["entry"].freshness == FreshnessTier.aging
|
|
1139
|
-
|
|
1140
|
-
@pytest.mark.asyncio
|
|
1141
|
-
async def test_validate_page_cached_stale(self):
|
|
1142
|
-
"""Should return stale for very old page."""
|
|
1143
|
-
state = _make_state_store()
|
|
1144
|
-
cache = _make_cache()
|
|
1145
|
-
service = MaterialCompletenessService(state, cache)
|
|
1146
|
-
|
|
1147
|
-
req = _make_requirement(material_type=MaterialType.page, identifier="88718940")
|
|
1148
|
-
entry = _make_cache_entry(age_hours=50.0)
|
|
1149
|
-
|
|
1150
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
1151
|
-
result = await service._validate_page_requirement(req, deep_check=False)
|
|
1152
|
-
|
|
1153
|
-
assert result["status"] == "stale"
|
|
1154
|
-
assert isinstance(result["entry"], StaleMaterial)
|
|
1155
|
-
assert result["entry"].stale_reason == "ttl_or_signal_mismatch"
|
|
1156
|
-
|
|
1157
|
-
@pytest.mark.asyncio
|
|
1158
|
-
async def test_validate_page_not_in_cache(self):
|
|
1159
|
-
"""Should return missing for uncached page."""
|
|
1160
|
-
state = _make_state_store()
|
|
1161
|
-
cache = _make_cache()
|
|
1162
|
-
service = MaterialCompletenessService(state, cache)
|
|
1163
|
-
|
|
1164
|
-
req = _make_requirement(material_type=MaterialType.page, identifier="88718940")
|
|
1165
|
-
|
|
1166
|
-
with patch.object(service.cache, "get_page_entry", return_value=None):
|
|
1167
|
-
result = await service._validate_page_requirement(req, deep_check=False)
|
|
1168
|
-
|
|
1169
|
-
assert result["status"] == "missing"
|
|
1170
|
-
assert isinstance(result["entry"], MissingMaterial)
|
|
1171
|
-
assert result["entry"].reason == "not_in_cache"
|
|
1172
|
-
|
|
1173
|
-
@pytest.mark.asyncio
|
|
1174
|
-
async def test_validate_page_preserves_title(self):
|
|
1175
|
-
"""Should preserve requirement title in result."""
|
|
1176
|
-
title = "My Important Page"
|
|
1177
|
-
state = _make_state_store()
|
|
1178
|
-
cache = _make_cache()
|
|
1179
|
-
service = MaterialCompletenessService(state, cache)
|
|
1180
|
-
|
|
1181
|
-
req = _make_requirement(material_type=MaterialType.page, identifier="88718940", title=title)
|
|
1182
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
1183
|
-
|
|
1184
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
1185
|
-
result = await service._validate_page_requirement(req, deep_check=False)
|
|
1186
|
-
|
|
1187
|
-
assert result["entry"].title == title
|
|
1188
|
-
|
|
1189
|
-
@pytest.mark.asyncio
|
|
1190
|
-
async def test_validate_page_captures_content_hash(self):
|
|
1191
|
-
"""Should capture content hash from cache entry."""
|
|
1192
|
-
state = _make_state_store()
|
|
1193
|
-
cache = _make_cache()
|
|
1194
|
-
service = MaterialCompletenessService(state, cache)
|
|
1195
|
-
|
|
1196
|
-
req = _make_requirement(material_type=MaterialType.page, identifier="88718940")
|
|
1197
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
1198
|
-
entry["sha256"] = "abc123"
|
|
1199
|
-
entry["hashes"] = {"html_sha256": "def456"}
|
|
1200
|
-
|
|
1201
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
1202
|
-
result = await service._validate_page_requirement(req, deep_check=False)
|
|
1203
|
-
|
|
1204
|
-
assert result["entry"].content_hash == "abc123"
|
|
1205
|
-
|
|
1206
|
-
@pytest.mark.asyncio
|
|
1207
|
-
async def test_validate_page_captures_cache_path(self):
|
|
1208
|
-
"""Should capture cache file path from entry."""
|
|
1209
|
-
state = _make_state_store()
|
|
1210
|
-
cache = _make_cache()
|
|
1211
|
-
service = MaterialCompletenessService(state, cache)
|
|
1212
|
-
|
|
1213
|
-
req = _make_requirement(material_type=MaterialType.page, identifier="88718940")
|
|
1214
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
1215
|
-
entry["cache_paths"] = {"html": "pages/88718940/page.html"}
|
|
1216
|
-
|
|
1217
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
1218
|
-
result = await service._validate_page_requirement(req, deep_check=False)
|
|
1219
|
-
|
|
1220
|
-
assert "pages/88718940/page.html" in result["entry"].cache_path or ""
|
|
1221
|
-
|
|
1222
|
-
@pytest.mark.asyncio
|
|
1223
|
-
async def test_validate_page_deep_check_with_remote_mismatch(self):
|
|
1224
|
-
"""Should mark stale when remote version differs."""
|
|
1225
|
-
state = _make_state_store()
|
|
1226
|
-
cache = _make_cache()
|
|
1227
|
-
service = MaterialCompletenessService(state, cache)
|
|
1228
|
-
|
|
1229
|
-
req = _make_requirement(material_type=MaterialType.page, identifier="88718940")
|
|
1230
|
-
entry = _make_cache_entry(age_hours=2.0, version="15")
|
|
1231
|
-
|
|
1232
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
1233
|
-
# Mock deep check detecting version mismatch
|
|
1234
|
-
with patch(
|
|
1235
|
-
"vds_audit_orchestrator.collectors.completeness.freshness_evaluator.FreshnessEvaluator.evaluate_freshness",
|
|
1236
|
-
return_value=FreshnessTier.stale,
|
|
1237
|
-
):
|
|
1238
|
-
result = await service._validate_page_requirement(req, deep_check=True)
|
|
1239
|
-
|
|
1240
|
-
assert result["status"] == "stale"
|
|
1241
|
-
|
|
1242
|
-
@pytest.mark.asyncio
|
|
1243
|
-
async def test_validate_page_without_cached_at(self):
|
|
1244
|
-
"""Should return unknown when cache entry has no cached_at."""
|
|
1245
|
-
state = _make_state_store()
|
|
1246
|
-
cache = _make_cache()
|
|
1247
|
-
service = MaterialCompletenessService(state, cache)
|
|
1248
|
-
|
|
1249
|
-
req = _make_requirement(material_type=MaterialType.page, identifier="88718940")
|
|
1250
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
1251
|
-
del entry["cached_at"]
|
|
1252
|
-
|
|
1253
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
1254
|
-
result = await service._validate_page_requirement(req, deep_check=False)
|
|
1255
|
-
|
|
1256
|
-
assert result["status"] == "missing"
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
class TestValidateAttachmentRequirement:
|
|
1260
|
-
"""Tests for attachment requirement cache validation (15 tests)."""
|
|
1261
|
-
|
|
1262
|
-
@pytest.mark.asyncio
|
|
1263
|
-
async def test_validate_attachment_cached_fresh(self):
|
|
1264
|
-
"""Should return prepared for fresh cached attachment."""
|
|
1265
|
-
state = _make_state_store()
|
|
1266
|
-
cache = _make_cache()
|
|
1267
|
-
service = MaterialCompletenessService(state, cache)
|
|
1268
|
-
|
|
1269
|
-
req = _make_requirement(material_type=MaterialType.attachment, identifier="att123")
|
|
1270
|
-
entry = _make_cache_entry(material_type=MaterialType.attachment, identifier="att123", age_hours=2.0)
|
|
1271
|
-
# For attachments, we need page_id in metadata
|
|
1272
|
-
req.metadata["page_id"] = "88718940"
|
|
1273
|
-
|
|
1274
|
-
with patch.object(service.cache, "get_attachment_entries", return_value=[entry]):
|
|
1275
|
-
result = await service._validate_attachment_requirement(req, deep_check=False)
|
|
1276
|
-
|
|
1277
|
-
assert result["status"] == "prepared"
|
|
1278
|
-
assert isinstance(result["entry"], PreparedMaterial)
|
|
1279
|
-
|
|
1280
|
-
@pytest.mark.asyncio
|
|
1281
|
-
async def test_validate_attachment_finds_by_page_id(self):
|
|
1282
|
-
"""Should scan cache to find attachment by page_id when not directly in metadata."""
|
|
1283
|
-
state = _make_state_store()
|
|
1284
|
-
cache = _make_cache()
|
|
1285
|
-
service = MaterialCompletenessService(state, cache)
|
|
1286
|
-
|
|
1287
|
-
req = _make_requirement(material_type=MaterialType.attachment, identifier="att123")
|
|
1288
|
-
# Don't set page_id in metadata, should scan cache
|
|
1289
|
-
|
|
1290
|
-
entry = _make_cache_entry(material_type=MaterialType.attachment, identifier="att123", age_hours=2.0)
|
|
1291
|
-
# attachment_id and page_id are already set by _make_cache_entry
|
|
1292
|
-
|
|
1293
|
-
# The implementation scans manifest first to find page_id, then calls get_attachment_entries
|
|
1294
|
-
# So we need get_attachment_entries to return the entry
|
|
1295
|
-
call_count = [0]
|
|
1296
|
-
|
|
1297
|
-
def mock_get_attachments(page_id, project_key=None):
|
|
1298
|
-
call_count[0] += 1
|
|
1299
|
-
return [entry]
|
|
1300
|
-
|
|
1301
|
-
with patch.object(service.cache, "get_attachment_entries", side_effect=mock_get_attachments):
|
|
1302
|
-
with patch.object(service.cache, "_manifest", new={"attachments": {"att123": entry}}):
|
|
1303
|
-
result = await service._validate_attachment_requirement(req, deep_check=False)
|
|
1304
|
-
|
|
1305
|
-
assert result["status"] == "prepared"
|
|
1306
|
-
|
|
1307
|
-
@pytest.mark.asyncio
|
|
1308
|
-
async def test_validate_attachment_not_in_cache(self):
|
|
1309
|
-
"""Should return missing for uncached attachment."""
|
|
1310
|
-
state = _make_state_store()
|
|
1311
|
-
cache = _make_cache()
|
|
1312
|
-
service = MaterialCompletenessService(state, cache)
|
|
1313
|
-
|
|
1314
|
-
req = _make_requirement(material_type=MaterialType.attachment, identifier="att123")
|
|
1315
|
-
|
|
1316
|
-
with patch.object(service.cache, "get_attachment_entries", return_value=[]):
|
|
1317
|
-
with patch.object(service.cache, "_manifest", new={"attachments": {}}):
|
|
1318
|
-
result = await service._validate_attachment_requirement(req, deep_check=False)
|
|
1319
|
-
|
|
1320
|
-
assert result["status"] == "missing"
|
|
1321
|
-
assert result["entry"].reason == "not_in_cache"
|
|
1322
|
-
|
|
1323
|
-
@pytest.mark.asyncio
|
|
1324
|
-
async def test_validate_attachment_matches_by_identifier(self):
|
|
1325
|
-
"""Should match attachment by attachment_id from list."""
|
|
1326
|
-
state = _make_state_store()
|
|
1327
|
-
cache = _make_cache()
|
|
1328
|
-
service = MaterialCompletenessService(state, cache)
|
|
1329
|
-
|
|
1330
|
-
req = _make_requirement(material_type=MaterialType.attachment, identifier="att123")
|
|
1331
|
-
|
|
1332
|
-
# Multiple attachments, should find matching one
|
|
1333
|
-
entries = [
|
|
1334
|
-
_make_cache_entry(material_type=MaterialType.attachment, identifier="att456", age_hours=2.0),
|
|
1335
|
-
_make_cache_entry(material_type=MaterialType.attachment, identifier="att123", age_hours=2.0),
|
|
1336
|
-
]
|
|
1337
|
-
|
|
1338
|
-
with patch.object(service.cache, "get_attachment_entries", return_value=entries):
|
|
1339
|
-
result = await service._validate_attachment_requirement(req, deep_check=False)
|
|
1340
|
-
|
|
1341
|
-
assert result["status"] == "prepared"
|
|
1342
|
-
assert result["entry"].identifier == "att123"
|
|
1343
|
-
|
|
1344
|
-
@pytest.mark.asyncio
|
|
1345
|
-
async def test_validate_attachment_aging_status(self):
|
|
1346
|
-
"""Should reflect aging status correctly."""
|
|
1347
|
-
state = _make_state_store()
|
|
1348
|
-
cache = _make_cache()
|
|
1349
|
-
service = MaterialCompletenessService(state, cache)
|
|
1350
|
-
|
|
1351
|
-
req = _make_requirement(material_type=MaterialType.attachment, identifier="att123")
|
|
1352
|
-
req.metadata["page_id"] = "88718940"
|
|
1353
|
-
entry = _make_cache_entry(material_type=MaterialType.attachment, identifier="att123", age_hours=30.0)
|
|
1354
|
-
|
|
1355
|
-
with patch.object(service.cache, "get_attachment_entries", return_value=[entry]):
|
|
1356
|
-
result = await service._validate_attachment_requirement(req, deep_check=False)
|
|
1357
|
-
|
|
1358
|
-
assert result["status"] == "prepared"
|
|
1359
|
-
assert result["entry"].freshness == FreshnessTier.aging
|
|
1360
|
-
|
|
1361
|
-
@pytest.mark.asyncio
|
|
1362
|
-
async def test_validate_attachment_stale_status(self):
|
|
1363
|
-
"""Should mark attachment as stale when too old."""
|
|
1364
|
-
state = _make_state_store()
|
|
1365
|
-
cache = _make_cache()
|
|
1366
|
-
service = MaterialCompletenessService(state, cache)
|
|
1367
|
-
|
|
1368
|
-
req = _make_requirement(material_type=MaterialType.attachment, identifier="att123")
|
|
1369
|
-
req.metadata["page_id"] = "88718940"
|
|
1370
|
-
entry = _make_cache_entry(material_type=MaterialType.attachment, identifier="att123", age_hours=50.0)
|
|
1371
|
-
|
|
1372
|
-
with patch.object(service.cache, "get_attachment_entries", return_value=[entry]):
|
|
1373
|
-
result = await service._validate_attachment_requirement(req, deep_check=False)
|
|
1374
|
-
|
|
1375
|
-
assert result["status"] == "stale"
|
|
1376
|
-
|
|
1377
|
-
@pytest.mark.asyncio
|
|
1378
|
-
async def test_validate_attachment_captures_file_hash(self):
|
|
1379
|
-
"""Should capture file hash from attachment entry."""
|
|
1380
|
-
state = _make_state_store()
|
|
1381
|
-
cache = _make_cache()
|
|
1382
|
-
service = MaterialCompletenessService(state, cache)
|
|
1383
|
-
|
|
1384
|
-
req = _make_requirement(material_type=MaterialType.attachment, identifier="att123")
|
|
1385
|
-
req.metadata["page_id"] = "88718940"
|
|
1386
|
-
entry = _make_cache_entry(material_type=MaterialType.attachment, identifier="att123", age_hours=2.0)
|
|
1387
|
-
entry["hashes"] = {"file_sha256": "file123"} # Use hashes dict instead of sha256
|
|
1388
|
-
|
|
1389
|
-
with patch.object(service.cache, "get_attachment_entries", return_value=[entry]):
|
|
1390
|
-
result = await service._validate_attachment_requirement(req, deep_check=False)
|
|
1391
|
-
|
|
1392
|
-
assert result["entry"].content_hash == "file123"
|
|
1393
|
-
|
|
1394
|
-
@pytest.mark.asyncio
|
|
1395
|
-
async def test_validate_attachment_without_page_metadata_scans_cache(self):
|
|
1396
|
-
"""Should scan cache manifest when page_id not in metadata."""
|
|
1397
|
-
state = _make_state_store()
|
|
1398
|
-
cache = _make_cache()
|
|
1399
|
-
service = MaterialCompletenessService(state, cache)
|
|
1400
|
-
|
|
1401
|
-
req = _make_requirement(material_type=MaterialType.attachment, identifier="att123")
|
|
1402
|
-
# No page_id in metadata
|
|
1403
|
-
|
|
1404
|
-
entry = _make_cache_entry(material_type=MaterialType.attachment, identifier="att123", age_hours=2.0)
|
|
1405
|
-
|
|
1406
|
-
# The scan finds page_id from manifest, then calls get_attachment_entries
|
|
1407
|
-
with patch.object(service.cache, "_manifest", new={"attachments": {"key": entry}}):
|
|
1408
|
-
with patch.object(service.cache, "get_attachment_entries", return_value=[entry]):
|
|
1409
|
-
result = await service._validate_attachment_requirement(req, deep_check=False)
|
|
1410
|
-
|
|
1411
|
-
assert result["status"] == "prepared"
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
class TestValidateRepoRequirement:
|
|
1415
|
-
"""Tests for repo requirement cache validation (15 tests)."""
|
|
1416
|
-
|
|
1417
|
-
@pytest.mark.asyncio
|
|
1418
|
-
async def test_validate_repo_cached_fresh(self):
|
|
1419
|
-
"""Should return prepared for fresh cached repo."""
|
|
1420
|
-
state = _make_state_store()
|
|
1421
|
-
cache = _make_cache()
|
|
1422
|
-
service = MaterialCompletenessService(state, cache)
|
|
1423
|
-
|
|
1424
|
-
req = _make_requirement(material_type=MaterialType.repo, identifier="merchant-report", project_key="PAR")
|
|
1425
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
1426
|
-
entry["repo"] = "merchant-report"
|
|
1427
|
-
|
|
1428
|
-
with patch.object(service.cache, "get_bitbucket_entries", return_value=[entry]):
|
|
1429
|
-
result = await service._validate_repo_requirement(req, deep_check=False)
|
|
1430
|
-
|
|
1431
|
-
assert result["status"] == "prepared"
|
|
1432
|
-
assert isinstance(result["entry"], PreparedMaterial)
|
|
1433
|
-
|
|
1434
|
-
@pytest.mark.asyncio
|
|
1435
|
-
async def test_validate_repo_not_in_cache(self):
|
|
1436
|
-
"""Should return missing for uncached repo."""
|
|
1437
|
-
state = _make_state_store()
|
|
1438
|
-
cache = _make_cache()
|
|
1439
|
-
service = MaterialCompletenessService(state, cache)
|
|
1440
|
-
|
|
1441
|
-
req = _make_requirement(material_type=MaterialType.repo, identifier="merchant-report", project_key="PAR")
|
|
1442
|
-
|
|
1443
|
-
with patch.object(service.cache, "get_bitbucket_entries", return_value=[]):
|
|
1444
|
-
result = await service._validate_repo_requirement(req, deep_check=False)
|
|
1445
|
-
|
|
1446
|
-
assert result["status"] == "missing"
|
|
1447
|
-
assert result["entry"].reason == "not_in_cache"
|
|
1448
|
-
|
|
1449
|
-
@pytest.mark.asyncio
|
|
1450
|
-
async def test_validate_repo_aging_status(self):
|
|
1451
|
-
"""Should reflect aging status for repo."""
|
|
1452
|
-
state = _make_state_store()
|
|
1453
|
-
cache = _make_cache()
|
|
1454
|
-
service = MaterialCompletenessService(state, cache)
|
|
1455
|
-
|
|
1456
|
-
req = _make_requirement(material_type=MaterialType.repo, identifier="merchant-report", project_key="PAR")
|
|
1457
|
-
entry = _make_cache_entry(age_hours=30.0)
|
|
1458
|
-
entry["repo"] = "merchant-report"
|
|
1459
|
-
|
|
1460
|
-
with patch.object(service.cache, "get_bitbucket_entries", return_value=[entry]):
|
|
1461
|
-
result = await service._validate_repo_requirement(req, deep_check=False)
|
|
1462
|
-
|
|
1463
|
-
assert result["status"] == "prepared"
|
|
1464
|
-
assert result["entry"].freshness == FreshnessTier.aging
|
|
1465
|
-
|
|
1466
|
-
@pytest.mark.asyncio
|
|
1467
|
-
async def test_validate_repo_stale_status(self):
|
|
1468
|
-
"""Should mark repo as stale when too old."""
|
|
1469
|
-
state = _make_state_store()
|
|
1470
|
-
cache = _make_cache()
|
|
1471
|
-
service = MaterialCompletenessService(state, cache)
|
|
1472
|
-
|
|
1473
|
-
req = _make_requirement(material_type=MaterialType.repo, identifier="merchant-report", project_key="PAR")
|
|
1474
|
-
entry = _make_cache_entry(age_hours=50.0)
|
|
1475
|
-
entry["repo"] = "merchant-report"
|
|
1476
|
-
|
|
1477
|
-
with patch.object(service.cache, "get_bitbucket_entries", return_value=[entry]):
|
|
1478
|
-
result = await service._validate_repo_requirement(req, deep_check=False)
|
|
1479
|
-
|
|
1480
|
-
assert result["status"] == "stale"
|
|
1481
|
-
|
|
1482
|
-
@pytest.mark.asyncio
|
|
1483
|
-
async def test_validate_repo_captures_repo_name(self):
|
|
1484
|
-
"""Should capture repo name from entry."""
|
|
1485
|
-
state = _make_state_store()
|
|
1486
|
-
cache = _make_cache()
|
|
1487
|
-
service = MaterialCompletenessService(state, cache)
|
|
1488
|
-
|
|
1489
|
-
req = _make_requirement(material_type=MaterialType.repo, identifier="merchant-report", project_key="PAR")
|
|
1490
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
1491
|
-
entry["repo"] = "merchant-report"
|
|
1492
|
-
entry["title"] = "Merchant Report Service"
|
|
1493
|
-
|
|
1494
|
-
with patch.object(service.cache, "get_bitbucket_entries", return_value=[entry]):
|
|
1495
|
-
result = await service._validate_repo_requirement(req, deep_check=False)
|
|
1496
|
-
|
|
1497
|
-
assert result["entry"].title == "Merchant Report Service"
|
|
1498
|
-
|
|
1499
|
-
@pytest.mark.asyncio
|
|
1500
|
-
async def test_validate_repo_captures_commit_hash(self):
|
|
1501
|
-
"""Should capture last commit hash from entry."""
|
|
1502
|
-
state = _make_state_store()
|
|
1503
|
-
cache = _make_cache()
|
|
1504
|
-
service = MaterialCompletenessService(state, cache)
|
|
1505
|
-
|
|
1506
|
-
req = _make_requirement(material_type=MaterialType.repo, identifier="merchant-report", project_key="PAR")
|
|
1507
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
1508
|
-
entry["repo"] = "merchant-report"
|
|
1509
|
-
entry["sha256"] = "abc123def"
|
|
1510
|
-
entry["last_commit"] = "abc123def"
|
|
1511
|
-
|
|
1512
|
-
with patch.object(service.cache, "get_bitbucket_entries", return_value=[entry]):
|
|
1513
|
-
result = await service._validate_repo_requirement(req, deep_check=False)
|
|
1514
|
-
|
|
1515
|
-
assert result["entry"].content_hash == "abc123def"
|
|
1516
|
-
|
|
1517
|
-
@pytest.mark.asyncio
|
|
1518
|
-
async def test_validate_repo_uses_first_match(self):
|
|
1519
|
-
"""Should use first entry when multiple repos match."""
|
|
1520
|
-
state = _make_state_store()
|
|
1521
|
-
cache = _make_cache()
|
|
1522
|
-
service = MaterialCompletenessService(state, cache)
|
|
1523
|
-
|
|
1524
|
-
req = _make_requirement(material_type=MaterialType.repo, identifier="merchant-report", project_key="PAR")
|
|
1525
|
-
|
|
1526
|
-
entries = [
|
|
1527
|
-
_make_cache_entry(age_hours=2.0),
|
|
1528
|
-
_make_cache_entry(age_hours=5.0),
|
|
1529
|
-
]
|
|
1530
|
-
for entry in entries:
|
|
1531
|
-
entry["repo"] = "merchant-report"
|
|
1532
|
-
|
|
1533
|
-
with patch.object(service.cache, "get_bitbucket_entries", return_value=entries):
|
|
1534
|
-
result = await service._validate_repo_requirement(req, deep_check=False)
|
|
1535
|
-
|
|
1536
|
-
assert result["status"] == "prepared"
|
|
1537
|
-
|
|
1538
|
-
@pytest.mark.asyncio
|
|
1539
|
-
async def test_validate_repo_unsupported_type(self):
|
|
1540
|
-
"""Should return missing for unsupported material type."""
|
|
1541
|
-
state = _make_state_store()
|
|
1542
|
-
cache = _make_cache()
|
|
1543
|
-
service = MaterialCompletenessService(state, cache)
|
|
1544
|
-
|
|
1545
|
-
req = _make_requirement(material_type=MaterialType.page, identifier="88718940")
|
|
1546
|
-
# Mark as unsupported via metadata
|
|
1547
|
-
req.metadata["unsupported_type"] = True
|
|
1548
|
-
|
|
1549
|
-
result = await service._validate_requirement(req, deep_check=False)
|
|
1550
|
-
|
|
1551
|
-
assert result["status"] == "missing"
|
|
1552
|
-
assert result["entry"].reason == "unsupported_type"
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
class TestValidateRequirement:
|
|
1556
|
-
"""Tests for main validate_requirement dispatcher (10 tests)."""
|
|
1557
|
-
|
|
1558
|
-
@pytest.mark.asyncio
|
|
1559
|
-
async def test_validate_requirement_dispatches_to_page(self):
|
|
1560
|
-
"""Should dispatch page requirements to page validator."""
|
|
1561
|
-
state = _make_state_store()
|
|
1562
|
-
cache = _make_cache()
|
|
1563
|
-
service = MaterialCompletenessService(state, cache)
|
|
1564
|
-
|
|
1565
|
-
req = _make_requirement(material_type=MaterialType.page)
|
|
1566
|
-
_make_cache_entry(age_hours=2.0)
|
|
1567
|
-
|
|
1568
|
-
with patch.object(
|
|
1569
|
-
service, "_validate_page_requirement", return_value={"status": "prepared", "entry": MagicMock()}
|
|
1570
|
-
):
|
|
1571
|
-
result = await service._validate_requirement(req, deep_check=False)
|
|
1572
|
-
|
|
1573
|
-
assert result["status"] == "prepared"
|
|
1574
|
-
|
|
1575
|
-
@pytest.mark.asyncio
|
|
1576
|
-
async def test_validate_requirement_dispatches_to_attachment(self):
|
|
1577
|
-
"""Should dispatch attachment requirements to attachment validator."""
|
|
1578
|
-
state = _make_state_store()
|
|
1579
|
-
cache = _make_cache()
|
|
1580
|
-
service = MaterialCompletenessService(state, cache)
|
|
1581
|
-
|
|
1582
|
-
req = _make_requirement(material_type=MaterialType.attachment)
|
|
1583
|
-
_make_cache_entry(age_hours=2.0)
|
|
1584
|
-
|
|
1585
|
-
with patch.object(
|
|
1586
|
-
service, "_validate_attachment_requirement", return_value={"status": "prepared", "entry": MagicMock()}
|
|
1587
|
-
):
|
|
1588
|
-
result = await service._validate_requirement(req, deep_check=False)
|
|
1589
|
-
|
|
1590
|
-
assert result["status"] == "prepared"
|
|
1591
|
-
|
|
1592
|
-
@pytest.mark.asyncio
|
|
1593
|
-
async def test_validate_requirement_dispatches_to_repo(self):
|
|
1594
|
-
"""Should dispatch repo requirements to repo validator."""
|
|
1595
|
-
state = _make_state_store()
|
|
1596
|
-
cache = _make_cache()
|
|
1597
|
-
service = MaterialCompletenessService(state, cache)
|
|
1598
|
-
|
|
1599
|
-
req = _make_requirement(material_type=MaterialType.repo)
|
|
1600
|
-
_make_cache_entry(age_hours=2.0)
|
|
1601
|
-
|
|
1602
|
-
with patch.object(
|
|
1603
|
-
service, "_validate_repo_requirement", return_value={"status": "prepared", "entry": MagicMock()}
|
|
1604
|
-
):
|
|
1605
|
-
result = await service._validate_requirement(req, deep_check=False)
|
|
1606
|
-
|
|
1607
|
-
assert result["status"] == "prepared"
|
|
1608
|
-
|
|
1609
|
-
@pytest.mark.asyncio
|
|
1610
|
-
async def test_validate_requirement_passes_deep_check_flag(self):
|
|
1611
|
-
"""Should pass deep_check flag to validators."""
|
|
1612
|
-
state = _make_state_store()
|
|
1613
|
-
cache = _make_cache()
|
|
1614
|
-
service = MaterialCompletenessService(state, cache)
|
|
1615
|
-
|
|
1616
|
-
req = _make_requirement(material_type=MaterialType.page)
|
|
1617
|
-
|
|
1618
|
-
with patch.object(
|
|
1619
|
-
service, "_validate_page_requirement", return_value={"status": "prepared", "entry": MagicMock()}
|
|
1620
|
-
) as mock_validate:
|
|
1621
|
-
await service._validate_requirement(req, deep_check=True)
|
|
1622
|
-
|
|
1623
|
-
mock_validate.assert_called_once_with(req, deep_check=True)
|
|
1624
|
-
|
|
1625
|
-
@pytest.mark.asyncio
|
|
1626
|
-
async def test_validate_requirement_unknown_type_missing(self):
|
|
1627
|
-
"""Should return missing for unknown material types."""
|
|
1628
|
-
state = _make_state_store()
|
|
1629
|
-
cache = _make_cache()
|
|
1630
|
-
service = MaterialCompletenessService(state, cache)
|
|
1631
|
-
|
|
1632
|
-
# Create a mock requirement with unsupported type
|
|
1633
|
-
from unittest.mock import Mock
|
|
1634
|
-
|
|
1635
|
-
req = Mock()
|
|
1636
|
-
req.material_type = "unknown_type" # type: ignore
|
|
1637
|
-
req.identifier = "test_id"
|
|
1638
|
-
req.project_key = "CEP"
|
|
1639
|
-
|
|
1640
|
-
result = await service._validate_requirement(req, deep_check=False)
|
|
1641
|
-
|
|
1642
|
-
assert result["status"] == "missing"
|
|
1643
|
-
assert result["entry"].reason == "unsupported_type"
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
# ===========================================================================
|
|
1647
|
-
# Metrics Computation Tests
|
|
1648
|
-
# ===========================================================================
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
class TestComputeMetrics:
|
|
1652
|
-
"""Tests for metrics computation (15 tests)."""
|
|
1653
|
-
|
|
1654
|
-
def test_compute_metrics_all_prepared(self):
|
|
1655
|
-
"""Should compute metrics when all materials prepared."""
|
|
1656
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1657
|
-
|
|
1658
|
-
requirements = [_make_requirement() for _ in range(10)]
|
|
1659
|
-
prepared = [_make_prepared() for _ in range(10)]
|
|
1660
|
-
missing = []
|
|
1661
|
-
stale = []
|
|
1662
|
-
|
|
1663
|
-
metrics = service._compute_metrics(requirements, prepared, missing, stale, deep_checked=False)
|
|
1664
|
-
|
|
1665
|
-
assert metrics.total_required == 10
|
|
1666
|
-
assert metrics.total_prepared == 10
|
|
1667
|
-
assert metrics.total_missing == 0
|
|
1668
|
-
assert metrics.total_stale == 0
|
|
1669
|
-
assert metrics.completeness_pct == 100.0
|
|
1670
|
-
|
|
1671
|
-
def test_compute_metrics_partial_prepared(self):
|
|
1672
|
-
"""Should compute metrics with some prepared materials."""
|
|
1673
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1674
|
-
|
|
1675
|
-
requirements = [_make_requirement() for _ in range(10)]
|
|
1676
|
-
prepared = [_make_prepared() for _ in range(7)]
|
|
1677
|
-
missing = [_make_missing() for _ in range(3)]
|
|
1678
|
-
stale = []
|
|
1679
|
-
|
|
1680
|
-
metrics = service._compute_metrics(requirements, prepared, missing, stale, deep_checked=False)
|
|
1681
|
-
|
|
1682
|
-
assert metrics.total_required == 10
|
|
1683
|
-
assert metrics.total_prepared == 7
|
|
1684
|
-
assert metrics.total_missing == 3
|
|
1685
|
-
assert metrics.completeness_pct == 70.0
|
|
1686
|
-
|
|
1687
|
-
def test_compute_metrics_with_stale(self):
|
|
1688
|
-
"""Should count stale materials correctly."""
|
|
1689
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1690
|
-
|
|
1691
|
-
requirements = [_make_requirement() for _ in range(10)]
|
|
1692
|
-
# 6 fresh, 2 aging, 2 stale
|
|
1693
|
-
prepared = [_make_prepared(freshness=FreshnessTier.fresh) for _ in range(6)] + [
|
|
1694
|
-
_make_prepared(freshness=FreshnessTier.aging) for _ in range(2)
|
|
1695
|
-
]
|
|
1696
|
-
missing = []
|
|
1697
|
-
stale = [_make_stale() for _ in range(2)]
|
|
1698
|
-
|
|
1699
|
-
metrics = service._compute_metrics(requirements, prepared, missing, stale, deep_checked=False)
|
|
1700
|
-
|
|
1701
|
-
assert metrics.total_prepared == 8
|
|
1702
|
-
assert metrics.total_stale == 2
|
|
1703
|
-
assert metrics.total_aging == 2
|
|
1704
|
-
|
|
1705
|
-
def test_compute_metrics_completeness_percentage_bounds(self):
|
|
1706
|
-
"""Should handle edge cases for percentage calculation."""
|
|
1707
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1708
|
-
|
|
1709
|
-
# 0% - no requirements
|
|
1710
|
-
metrics = service._compute_metrics([], [], [], [], deep_checked=False)
|
|
1711
|
-
assert metrics.completeness_pct == 100.0 # Empty case
|
|
1712
|
-
|
|
1713
|
-
# Normal case
|
|
1714
|
-
requirements = [_make_requirement() for _ in range(5)]
|
|
1715
|
-
prepared = [_make_prepared() for _ in range(3)]
|
|
1716
|
-
metrics = service._compute_metrics(requirements, prepared, [], [], deep_checked=False)
|
|
1717
|
-
assert metrics.completeness_pct == 60.0
|
|
1718
|
-
|
|
1719
|
-
def test_compute_metrics_freshness_percentage(self):
|
|
1720
|
-
"""Should calculate freshness percentage correctly."""
|
|
1721
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1722
|
-
|
|
1723
|
-
# All fresh = 100% freshness
|
|
1724
|
-
prepared = [_make_prepared(freshness=FreshnessTier.fresh) for _ in range(5)]
|
|
1725
|
-
metrics = service._compute_metrics(
|
|
1726
|
-
[_make_requirement() for _ in range(5)], prepared, [], [], deep_checked=False
|
|
1727
|
-
)
|
|
1728
|
-
assert metrics.freshness_pct == 100.0
|
|
1729
|
-
|
|
1730
|
-
# Mix: 3 fresh, 2 aging = 60% freshness
|
|
1731
|
-
prepared = [_make_prepared(freshness=FreshnessTier.fresh) for _ in range(3)] + [
|
|
1732
|
-
_make_prepared(freshness=FreshnessTier.aging) for _ in range(2)
|
|
1733
|
-
]
|
|
1734
|
-
metrics = service._compute_metrics(
|
|
1735
|
-
[_make_requirement() for _ in range(5)], prepared, [], [], deep_checked=False
|
|
1736
|
-
)
|
|
1737
|
-
assert metrics.freshness_pct == 60.0
|
|
1738
|
-
|
|
1739
|
-
def test_compute_metrics_freshness_percentage_no_prepared(self):
|
|
1740
|
-
"""Should handle no prepared materials."""
|
|
1741
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1742
|
-
|
|
1743
|
-
metrics = service._compute_metrics(
|
|
1744
|
-
[_make_requirement() for _ in range(5)], [], [_make_missing() for _ in range(5)], [], deep_checked=False
|
|
1745
|
-
)
|
|
1746
|
-
assert metrics.freshness_pct == 100.0 # By definition when no prepared
|
|
1747
|
-
|
|
1748
|
-
def test_compute_metrics_average_age(self):
|
|
1749
|
-
"""Should calculate average age of cached materials."""
|
|
1750
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1751
|
-
|
|
1752
|
-
prepared = [
|
|
1753
|
-
_make_prepared(age_hours=2.0),
|
|
1754
|
-
_make_prepared(age_hours=4.0),
|
|
1755
|
-
_make_prepared(age_hours=6.0),
|
|
1756
|
-
]
|
|
1757
|
-
|
|
1758
|
-
metrics = service._compute_metrics(
|
|
1759
|
-
[_make_requirement() for _ in range(3)], prepared, [], [], deep_checked=False
|
|
1760
|
-
)
|
|
1761
|
-
assert metrics.avg_freshness_hours == 4.0
|
|
1762
|
-
|
|
1763
|
-
def test_compute_metrics_average_age_empty(self):
|
|
1764
|
-
"""Should return 0 for average age when no materials prepared."""
|
|
1765
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1766
|
-
|
|
1767
|
-
metrics = service._compute_metrics([], [], [], [], deep_checked=False)
|
|
1768
|
-
assert metrics.avg_freshness_hours == 0.0
|
|
1769
|
-
|
|
1770
|
-
def test_compute_metrics_cache_hit_rate(self):
|
|
1771
|
-
"""Should calculate cache hit rate."""
|
|
1772
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1773
|
-
|
|
1774
|
-
requirements = [_make_requirement() for _ in range(10)]
|
|
1775
|
-
prepared = [_make_prepared() for _ in range(8)]
|
|
1776
|
-
missing = [_make_missing() for _ in range(2)]
|
|
1777
|
-
|
|
1778
|
-
metrics = service._compute_metrics(requirements, prepared, missing, [], deep_checked=False)
|
|
1779
|
-
assert metrics.cache_hit_rate == 80.0
|
|
1780
|
-
|
|
1781
|
-
def test_compute_metrics_deep_checked_flag(self):
|
|
1782
|
-
"""Should reflect deep check status."""
|
|
1783
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1784
|
-
|
|
1785
|
-
metrics = service._compute_metrics([], [], [], [], deep_checked=False)
|
|
1786
|
-
assert metrics.deep_checked is False
|
|
1787
|
-
|
|
1788
|
-
metrics = service._compute_metrics([], [], [], [], deep_checked=True)
|
|
1789
|
-
assert metrics.deep_checked is True
|
|
1790
|
-
|
|
1791
|
-
def test_compute_metrics_timestamp(self):
|
|
1792
|
-
"""Should include checked_at timestamp."""
|
|
1793
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1794
|
-
|
|
1795
|
-
before = datetime.now(UTC)
|
|
1796
|
-
metrics = service._compute_metrics([], [], [], [], deep_checked=False)
|
|
1797
|
-
after = datetime.now(UTC)
|
|
1798
|
-
|
|
1799
|
-
assert before <= metrics.checked_at <= after
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
# ===========================================================================
|
|
1803
|
-
# Action Generation Tests
|
|
1804
|
-
# ===========================================================================
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
class TestGenerateActions:
|
|
1808
|
-
"""Tests for action generation (15 tests)."""
|
|
1809
|
-
|
|
1810
|
-
def test_generate_actions_for_missing_materials(self):
|
|
1811
|
-
"""Should generate download action for missing materials."""
|
|
1812
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1813
|
-
|
|
1814
|
-
metrics = _make_metrics(total_required=10, total_prepared=7, total_missing=3, completeness_pct=70.0)
|
|
1815
|
-
missing = [_make_missing(identifier="m1"), _make_missing(identifier="m2"), _make_missing(identifier="m3")]
|
|
1816
|
-
stale = []
|
|
1817
|
-
|
|
1818
|
-
actions = service._generate_actions(metrics, missing, stale, min_threshold_pct=80.0)
|
|
1819
|
-
|
|
1820
|
-
assert len(actions) >= 1
|
|
1821
|
-
download_actions = [a for a in actions if a.action_type == "download"]
|
|
1822
|
-
assert len(download_actions) == 1
|
|
1823
|
-
assert (
|
|
1824
|
-
download_actions[0].priority == "high"
|
|
1825
|
-
) # Changed: 70% is close to 80% threshold, so "high" not "critical"
|
|
1826
|
-
assert "3 missing materials" in download_actions[0].description
|
|
1827
|
-
|
|
1828
|
-
def test_generate_actions_for_stale_materials(self):
|
|
1829
|
-
"""Should generate refresh action for stale materials."""
|
|
1830
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1831
|
-
|
|
1832
|
-
metrics = _make_metrics(total_required=10, total_prepared=10, total_stale=2, completeness_pct=100.0)
|
|
1833
|
-
missing = []
|
|
1834
|
-
stale = [_make_stale(identifier="s1"), _make_stale(identifier="s2")]
|
|
1835
|
-
|
|
1836
|
-
actions = service._generate_actions(metrics, missing, stale, min_threshold_pct=80.0)
|
|
1837
|
-
|
|
1838
|
-
refresh_actions = [a for a in actions if a.action_type == "refresh"]
|
|
1839
|
-
assert len(refresh_actions) == 1
|
|
1840
|
-
assert refresh_actions[0].priority == "medium"
|
|
1841
|
-
|
|
1842
|
-
def test_generate_actions_below_threshold(self):
|
|
1843
|
-
"""Should generate deep_check action when below threshold."""
|
|
1844
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1845
|
-
|
|
1846
|
-
metrics = _make_metrics(total_required=10, total_prepared=5, completeness_pct=50.0)
|
|
1847
|
-
missing = [_make_missing() for _ in range(5)]
|
|
1848
|
-
stale = []
|
|
1849
|
-
|
|
1850
|
-
actions = service._generate_actions(metrics, missing, stale, min_threshold_pct=80.0)
|
|
1851
|
-
|
|
1852
|
-
check_actions = [a for a in actions if a.action_type == "deep_check"]
|
|
1853
|
-
assert len(check_actions) == 1
|
|
1854
|
-
assert "below threshold" in check_actions[0].description.lower()
|
|
1855
|
-
|
|
1856
|
-
def test_generate_actions_all_good(self):
|
|
1857
|
-
"""Should generate ignore action when all materials prepared."""
|
|
1858
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1859
|
-
|
|
1860
|
-
metrics = _make_metrics(total_required=10, total_prepared=10, completeness_pct=100.0)
|
|
1861
|
-
missing = []
|
|
1862
|
-
stale = []
|
|
1863
|
-
|
|
1864
|
-
actions = service._generate_actions(metrics, missing, stale, min_threshold_pct=80.0)
|
|
1865
|
-
|
|
1866
|
-
assert len(actions) == 1
|
|
1867
|
-
assert actions[0].action_type == "ignore"
|
|
1868
|
-
assert actions[0].priority == "low"
|
|
1869
|
-
|
|
1870
|
-
def test_generate_actions_high_priority_missing(self):
|
|
1871
|
-
"""Should use critical priority when completeness very low."""
|
|
1872
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1873
|
-
|
|
1874
|
-
metrics = _make_metrics(total_required=10, total_prepared=2, completeness_pct=20.0)
|
|
1875
|
-
missing = [_make_missing() for _ in range(8)]
|
|
1876
|
-
|
|
1877
|
-
actions = service._generate_actions(metrics, missing, [], min_threshold_pct=80.0)
|
|
1878
|
-
|
|
1879
|
-
download_actions = [a for a in actions if a.action_type == "download"]
|
|
1880
|
-
assert download_actions[0].priority == "critical"
|
|
1881
|
-
|
|
1882
|
-
def test_generate_actions_high_priority_with_threshold(self):
|
|
1883
|
-
"""Should use high priority when completeness close to threshold."""
|
|
1884
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1885
|
-
|
|
1886
|
-
metrics = _make_metrics(total_required=10, total_prepared=7, completeness_pct=70.0)
|
|
1887
|
-
missing = [_make_missing() for _ in range(3)]
|
|
1888
|
-
|
|
1889
|
-
actions = service._generate_actions(metrics, missing, [], min_threshold_pct=80.0)
|
|
1890
|
-
|
|
1891
|
-
download_actions = [a for a in actions if a.action_type == "download"]
|
|
1892
|
-
assert download_actions[0].priority == "high" # Not critical but below threshold
|
|
1893
|
-
|
|
1894
|
-
def test_generate_actions_includes_affected_materials(self):
|
|
1895
|
-
"""Should list affected materials in action."""
|
|
1896
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1897
|
-
|
|
1898
|
-
metrics = _make_metrics()
|
|
1899
|
-
missing = [
|
|
1900
|
-
_make_missing(identifier="page1"),
|
|
1901
|
-
_make_missing(identifier="page2"),
|
|
1902
|
-
]
|
|
1903
|
-
stale = []
|
|
1904
|
-
|
|
1905
|
-
actions = service._generate_actions(metrics, missing, stale, min_threshold_pct=80.0)
|
|
1906
|
-
|
|
1907
|
-
download_actions = [a for a in actions if a.action_type == "download"]
|
|
1908
|
-
assert len(download_actions[0].affected_materials) == 2
|
|
1909
|
-
assert "page1" in download_actions[0].affected_materials
|
|
1910
|
-
assert "page2" in download_actions[0].affected_materials
|
|
1911
|
-
|
|
1912
|
-
def test_generate_actions_limits_affected_materials(self):
|
|
1913
|
-
"""Should limit affected materials list in description."""
|
|
1914
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1915
|
-
|
|
1916
|
-
metrics = _make_metrics()
|
|
1917
|
-
# Create 7 missing materials to test truncation
|
|
1918
|
-
missing = [_make_missing(identifier=f"page{i}") for i in range(7)]
|
|
1919
|
-
stale = []
|
|
1920
|
-
|
|
1921
|
-
actions = service._generate_actions(metrics, missing, stale, min_threshold_pct=80.0)
|
|
1922
|
-
|
|
1923
|
-
download_actions = [a for a in actions if a.action_type == "download"]
|
|
1924
|
-
# Should list first 5 plus "and 2 more"
|
|
1925
|
-
assert "5" in download_actions[0].description
|
|
1926
|
-
assert "2 more" in download_actions[0].description
|
|
1927
|
-
|
|
1928
|
-
def test_generate_actions_includes_command_suggestion(self):
|
|
1929
|
-
"""Should include CLI command suggestion for download action."""
|
|
1930
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1931
|
-
|
|
1932
|
-
metrics = _make_metrics(project_key="88718940")
|
|
1933
|
-
missing = [_make_missing()]
|
|
1934
|
-
stale = []
|
|
1935
|
-
|
|
1936
|
-
actions = service._generate_actions(metrics, missing, stale, min_threshold_pct=80.0)
|
|
1937
|
-
|
|
1938
|
-
download_actions = [a for a in actions if a.action_type == "download"]
|
|
1939
|
-
assert "vds-audit extract-docs" in download_actions[0].command_suggestion
|
|
1940
|
-
|
|
1941
|
-
def test_generate_actions_refresh_command_suggestion(self):
|
|
1942
|
-
"""Should include CLI command suggestion for refresh action."""
|
|
1943
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1944
|
-
|
|
1945
|
-
metrics = _make_metrics(project_key="88718940")
|
|
1946
|
-
missing = []
|
|
1947
|
-
stale = [_make_stale()]
|
|
1948
|
-
|
|
1949
|
-
actions = service._generate_actions(metrics, missing, stale, min_threshold_pct=80.0)
|
|
1950
|
-
|
|
1951
|
-
refresh_actions = [a for a in actions if a.action_type == "refresh"]
|
|
1952
|
-
assert "vds-audit extract-docs" in refresh_actions[0].command_suggestion
|
|
1953
|
-
assert "--refresh" in refresh_actions[0].command_suggestion
|
|
1954
|
-
|
|
1955
|
-
def test_generate_actions_estimates_effort(self):
|
|
1956
|
-
"""Should include estimated effort in actions."""
|
|
1957
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1958
|
-
|
|
1959
|
-
metrics = _make_metrics()
|
|
1960
|
-
missing = [_make_missing(), _make_missing()]
|
|
1961
|
-
stale = []
|
|
1962
|
-
|
|
1963
|
-
actions = service._generate_actions(metrics, missing, stale, min_threshold_pct=80.0)
|
|
1964
|
-
|
|
1965
|
-
download_actions = [a for a in actions if a.action_type == "download"]
|
|
1966
|
-
assert "~4 minutes" in download_actions[0].estimated_effort
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
# ===========================================================================
|
|
1970
|
-
# Helper Method Tests
|
|
1971
|
-
# ===========================================================================
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
class TestHelperMethods:
|
|
1975
|
-
"""Tests for helper utility methods (20 tests)."""
|
|
1976
|
-
|
|
1977
|
-
def test_summarize_sources_empty(self):
|
|
1978
|
-
"""Should return empty dict for no requirements."""
|
|
1979
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1980
|
-
|
|
1981
|
-
summary = service._summarize_sources([])
|
|
1982
|
-
|
|
1983
|
-
assert summary == {}
|
|
1984
|
-
|
|
1985
|
-
def test_summarize_sources_single_source(self):
|
|
1986
|
-
"""Should count requirements by source."""
|
|
1987
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
1988
|
-
|
|
1989
|
-
requirements = [
|
|
1990
|
-
_make_requirement(source="registry"),
|
|
1991
|
-
_make_requirement(source="registry"),
|
|
1992
|
-
_make_requirement(source="checklist"),
|
|
1993
|
-
]
|
|
1994
|
-
|
|
1995
|
-
summary = service._summarize_sources(requirements)
|
|
1996
|
-
|
|
1997
|
-
assert summary == {"registry": 2, "checklist": 1}
|
|
1998
|
-
|
|
1999
|
-
def test_summarize_sources_multiple_sources(self):
|
|
2000
|
-
"""Should handle all source types."""
|
|
2001
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
2002
|
-
|
|
2003
|
-
requirements = [
|
|
2004
|
-
_make_requirement(source="registry"),
|
|
2005
|
-
_make_requirement(source="checklist"),
|
|
2006
|
-
_make_requirement(source="explicit"),
|
|
2007
|
-
_make_requirement(source="explicit"),
|
|
2008
|
-
]
|
|
2009
|
-
|
|
2010
|
-
summary = service._summarize_sources(requirements)
|
|
2011
|
-
|
|
2012
|
-
assert summary["registry"] == 1
|
|
2013
|
-
assert summary["checklist"] == 1
|
|
2014
|
-
assert summary["explicit"] == 2
|
|
2015
|
-
|
|
2016
|
-
def test_requirement_key_uniqueness(self):
|
|
2017
|
-
"""Should generate unique keys considering material type."""
|
|
2018
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
2019
|
-
|
|
2020
|
-
page_req = _make_requirement(material_type=MaterialType.page, identifier="123")
|
|
2021
|
-
attachment_req = _make_requirement(material_type=MaterialType.attachment, identifier="123")
|
|
2022
|
-
|
|
2023
|
-
page_key = service._requirement_key(page_req)
|
|
2024
|
-
attachment_key = service._requirement_key(attachment_req)
|
|
2025
|
-
|
|
2026
|
-
assert page_key != attachment_key
|
|
2027
|
-
assert "page:" in page_key
|
|
2028
|
-
assert "attachment:" in attachment_key
|
|
2029
|
-
|
|
2030
|
-
def test_requirement_key_includes_project_key(self):
|
|
2031
|
-
"""Should include project key in deduplication key."""
|
|
2032
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
2033
|
-
|
|
2034
|
-
req = _make_requirement(project_key="CEP", identifier="123")
|
|
2035
|
-
|
|
2036
|
-
key = service._requirement_key(req)
|
|
2037
|
-
|
|
2038
|
-
assert "CEP" in key
|
|
2039
|
-
assert "123" in key
|
|
2040
|
-
|
|
2041
|
-
def test_extract_page_id_from_pageId_param(self):
|
|
2042
|
-
"""Should extract pageId from URL parameter."""
|
|
2043
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
2044
|
-
|
|
2045
|
-
page_id = service._extract_page_id_from_url("http://confluence?pageId=88718940")
|
|
2046
|
-
|
|
2047
|
-
assert page_id == "88718940"
|
|
2048
|
-
|
|
2049
|
-
def test_extract_page_id_from_pages_format(self):
|
|
2050
|
-
"""Should extract pageId from /pages/ format."""
|
|
2051
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
2052
|
-
|
|
2053
|
-
page_id = service._extract_page_id_from_url("http://confluence/pages/88718940")
|
|
2054
|
-
|
|
2055
|
-
assert page_id == "88718940"
|
|
2056
|
-
|
|
2057
|
-
def test_extract_page_id_returns_none_for_no_match(self):
|
|
2058
|
-
"""Should return None when no page_id found."""
|
|
2059
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
2060
|
-
|
|
2061
|
-
page_id = service._extract_page_id_from_url("http://example.com/page")
|
|
2062
|
-
|
|
2063
|
-
assert page_id is None
|
|
2064
|
-
|
|
2065
|
-
def test_extract_page_id_handles_various_formats(self):
|
|
2066
|
-
"""Should handle different URL formats."""
|
|
2067
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
2068
|
-
|
|
2069
|
-
# With pageId parameter
|
|
2070
|
-
assert service._extract_page_id_from_url("http://c?pageId=123") == "123"
|
|
2071
|
-
# With /pages/ format
|
|
2072
|
-
assert service._extract_page_id_from_url("http://c/pages/456") == "456"
|
|
2073
|
-
# With uppercase parameter
|
|
2074
|
-
assert service._extract_page_id_from_url("http://c?PAGEID=789") is None # case-sensitive
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
# ===========================================================================
|
|
2078
|
-
# Main Entry Point Tests
|
|
2079
|
-
# ===========================================================================
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
class TestCheckCompleteness:
|
|
2083
|
-
"""Tests for check_completeness main workflow (30 tests)."""
|
|
2084
|
-
|
|
2085
|
-
@pytest.mark.asyncio
|
|
2086
|
-
async def test_check_completeness_full_workflow(self):
|
|
2087
|
-
"""Should execute full completeness check workflow."""
|
|
2088
|
-
state = _make_state_store(
|
|
2089
|
-
project_links=[
|
|
2090
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/88718940"},
|
|
2091
|
-
],
|
|
2092
|
-
project_preparation={"sync_metadata": {"artifacts": [{"page_id": "88718940", "type": "page"}]}},
|
|
2093
|
-
)
|
|
2094
|
-
cache = _make_cache()
|
|
2095
|
-
service = MaterialCompletenessService(state, cache)
|
|
2096
|
-
|
|
2097
|
-
# Mock cache to return prepared entry
|
|
2098
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2099
|
-
|
|
2100
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2101
|
-
report = await service.check_completeness("88718940", deep_check=False)
|
|
2102
|
-
|
|
2103
|
-
assert isinstance(report, CompletenessReport)
|
|
2104
|
-
assert report.project_key == "88718940"
|
|
2105
|
-
assert report.metrics.total_required >= 1
|
|
2106
|
-
assert report.deep_checked is False
|
|
2107
|
-
|
|
2108
|
-
@pytest.mark.asyncio
|
|
2109
|
-
async def test_check_completeness_with_explicit_requirements(self):
|
|
2110
|
-
"""Should accept explicit requirement overrides."""
|
|
2111
|
-
state = _make_state_store()
|
|
2112
|
-
cache = _make_cache()
|
|
2113
|
-
service = MaterialCompletenessService(state, cache)
|
|
2114
|
-
|
|
2115
|
-
explicit = [_make_requirement(identifier="explicit-page")]
|
|
2116
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2117
|
-
|
|
2118
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2119
|
-
report = await service.check_completeness("88718940", explicit_requirements=explicit)
|
|
2120
|
-
|
|
2121
|
-
assert report.metrics.total_required >= 1
|
|
2122
|
-
|
|
2123
|
-
@pytest.mark.asyncio
|
|
2124
|
-
async def test_check_completeness_with_deep_check(self):
|
|
2125
|
-
"""Should respect deep_check flag."""
|
|
2126
|
-
state = _make_state_store()
|
|
2127
|
-
cache = _make_cache()
|
|
2128
|
-
service = MaterialCompletenessService(state, cache)
|
|
2129
|
-
|
|
2130
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2131
|
-
|
|
2132
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2133
|
-
report = await service.check_completeness("88718940", deep_check=True)
|
|
2134
|
-
|
|
2135
|
-
assert report.deep_checked is True
|
|
2136
|
-
|
|
2137
|
-
@pytest.mark.asyncio
|
|
2138
|
-
async def test_check_completeness_custom_threshold(self):
|
|
2139
|
-
"""Should use custom threshold for readiness determination."""
|
|
2140
|
-
state = _make_state_store()
|
|
2141
|
-
cache = _make_cache()
|
|
2142
|
-
service = MaterialCompletenessService(state, cache)
|
|
2143
|
-
|
|
2144
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2145
|
-
|
|
2146
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2147
|
-
report = await service.check_completeness("88718940", min_threshold_pct=90.0)
|
|
2148
|
-
|
|
2149
|
-
# Threshold affects action generation
|
|
2150
|
-
actions = report.actions
|
|
2151
|
-
if report.metrics.completeness_pct < 90:
|
|
2152
|
-
assert any(a.action_type == "deep_check" for a in actions)
|
|
2153
|
-
|
|
2154
|
-
@pytest.mark.asyncio
|
|
2155
|
-
async def test_check_completeness_custom_cache_dir(self, tmp_path: Path):
|
|
2156
|
-
"""Should use custom cache directory when provided."""
|
|
2157
|
-
state = _make_state_store()
|
|
2158
|
-
cache = _make_cache()
|
|
2159
|
-
service = MaterialCompletenessService(state, cache)
|
|
2160
|
-
|
|
2161
|
-
custom_cache = tmp_path / "custom_cache"
|
|
2162
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2163
|
-
|
|
2164
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2165
|
-
report = await service.check_completeness("88718940", cache_dir=custom_cache)
|
|
2166
|
-
|
|
2167
|
-
assert report.cache_dir == str(custom_cache)
|
|
2168
|
-
|
|
2169
|
-
@pytest.mark.asyncio
|
|
2170
|
-
async def test_check_completeness_generates_report_with_all_fields(self):
|
|
2171
|
-
"""Should generate report with all required fields."""
|
|
2172
|
-
state = _make_state_store()
|
|
2173
|
-
cache = _make_cache()
|
|
2174
|
-
service = MaterialCompletenessService(state, cache)
|
|
2175
|
-
|
|
2176
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2177
|
-
|
|
2178
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2179
|
-
report = await service.check_completeness("88718940")
|
|
2180
|
-
|
|
2181
|
-
# Check all top-level fields
|
|
2182
|
-
assert hasattr(report, "metrics")
|
|
2183
|
-
assert hasattr(report, "prepared")
|
|
2184
|
-
assert hasattr(report, "missing")
|
|
2185
|
-
assert hasattr(report, "stale")
|
|
2186
|
-
hasattr(report, "actions")
|
|
2187
|
-
assert hasattr(report, "project_key")
|
|
2188
|
-
assert hasattr(report, "checked_at")
|
|
2189
|
-
assert hasattr(report, "deep_checked")
|
|
2190
|
-
assert hasattr(report, "cache_dir")
|
|
2191
|
-
assert hasattr(report, "source_summary")
|
|
2192
|
-
|
|
2193
|
-
@pytest.mark.asyncio
|
|
2194
|
-
async def test_check_completeness_handles_requirement_discovery_error(self):
|
|
2195
|
-
"""Should handle RequirementDiscoveryError gracefully."""
|
|
2196
|
-
state = _make_state_store()
|
|
2197
|
-
cache = _make_cache()
|
|
2198
|
-
service = MaterialCompletenessService(state, cache)
|
|
2199
|
-
|
|
2200
|
-
# Mock discovery to raise error
|
|
2201
|
-
with patch.object(service, "_discover_requirements", side_effect=RequirementDiscoveryError("Test error")):
|
|
2202
|
-
with pytest.raises(RequirementDiscoveryError):
|
|
2203
|
-
await service.check_completeness("88718940")
|
|
2204
|
-
|
|
2205
|
-
@pytest.mark.asyncio
|
|
2206
|
-
async def test_check_completeness_includes_source_summary(self):
|
|
2207
|
-
"""Should include source summary in report."""
|
|
2208
|
-
state = _make_state_store(
|
|
2209
|
-
project_links=[
|
|
2210
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/111"},
|
|
2211
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/222"},
|
|
2212
|
-
],
|
|
2213
|
-
)
|
|
2214
|
-
cache = _make_cache()
|
|
2215
|
-
service = MaterialCompletenessService(state, cache)
|
|
2216
|
-
|
|
2217
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2218
|
-
|
|
2219
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2220
|
-
report = await service.check_completeness("88718940")
|
|
2221
|
-
|
|
2222
|
-
assert "registry" in report.source_summary
|
|
2223
|
-
assert report.source_summary["registry"] >= 2
|
|
2224
|
-
|
|
2225
|
-
@pytest.mark.asyncio
|
|
2226
|
-
async def test_check_completeness_empty_requirements(self):
|
|
2227
|
-
"""Should handle case with no requirements."""
|
|
2228
|
-
state = _make_state_store()
|
|
2229
|
-
cache = _make_cache()
|
|
2230
|
-
service = MaterialCompletenessService(state, cache)
|
|
2231
|
-
|
|
2232
|
-
report = await service.check_completeness("88718940")
|
|
2233
|
-
|
|
2234
|
-
assert report.metrics.total_required == 0
|
|
2235
|
-
assert report.metrics.completeness_pct == 100.0
|
|
2236
|
-
|
|
2237
|
-
@pytest.mark.asyncio
|
|
2238
|
-
async def test_check_completeness_all_missing(self):
|
|
2239
|
-
"""Should handle case with all materials missing."""
|
|
2240
|
-
state = _make_state_store()
|
|
2241
|
-
cache = _make_cache()
|
|
2242
|
-
service = MaterialCompletenessService(state, cache)
|
|
2243
|
-
|
|
2244
|
-
# Create 5 requirements with different identifiers
|
|
2245
|
-
requirements = [_make_requirement(identifier=f"page{i}") for i in range(5)]
|
|
2246
|
-
|
|
2247
|
-
with patch.object(service, "_discover_requirements", return_value=requirements):
|
|
2248
|
-
with patch.object(service.cache, "get_page_entry", return_value=None):
|
|
2249
|
-
report = await service.check_completeness("88718940")
|
|
2250
|
-
|
|
2251
|
-
assert report.metrics.total_missing == 5
|
|
2252
|
-
assert report.metrics.completeness_pct == 0.0
|
|
2253
|
-
assert len(report.missing) == 5
|
|
2254
|
-
|
|
2255
|
-
@pytest.mark.asyncio
|
|
2256
|
-
async def test_check_completeness_generates_actions(self):
|
|
2257
|
-
"""Should generate appropriate actions."""
|
|
2258
|
-
state = _make_state_store()
|
|
2259
|
-
cache = _make_cache()
|
|
2260
|
-
service = MaterialCompletenessService(state, cache)
|
|
2261
|
-
|
|
2262
|
-
requirements = [_make_requirement() for _ in range(5)]
|
|
2263
|
-
|
|
2264
|
-
with patch.object(service, "_discover_requirements", return_value=requirements):
|
|
2265
|
-
with patch.object(service.cache, "get_page_entry", return_value=None):
|
|
2266
|
-
report = await service.check_completeness("88718940")
|
|
2267
|
-
|
|
2268
|
-
assert len(report.actions) >= 1
|
|
2269
|
-
|
|
2270
|
-
@pytest.mark.asyncio
|
|
2271
|
-
async def test_check_completeness_records_duration(self):
|
|
2272
|
-
"""Should log execution time (telemetry)."""
|
|
2273
|
-
state = _make_state_store()
|
|
2274
|
-
cache = _make_cache()
|
|
2275
|
-
service = MaterialCompletenessService(state, cache)
|
|
2276
|
-
|
|
2277
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2278
|
-
|
|
2279
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2280
|
-
report = await service.check_completeness("88718940")
|
|
2281
|
-
|
|
2282
|
-
# Just verify it completes - actual logging would be tested in integration
|
|
2283
|
-
assert report is not None
|
|
2284
|
-
|
|
2285
|
-
@pytest.mark.asyncio
|
|
2286
|
-
async def test_check_completeness_with_multiple_material_types(self):
|
|
2287
|
-
"""Should handle pages, attachments, and repos together."""
|
|
2288
|
-
state = _make_state_store()
|
|
2289
|
-
cache = _make_cache()
|
|
2290
|
-
service = MaterialCompletenessService(state, cache)
|
|
2291
|
-
|
|
2292
|
-
requirements = [
|
|
2293
|
-
_make_requirement(material_type=MaterialType.page, identifier="p1"),
|
|
2294
|
-
_make_requirement(material_type=MaterialType.attachment, identifier="a1"),
|
|
2295
|
-
_make_requirement(material_type=MaterialType.repo, identifier="repo1"),
|
|
2296
|
-
]
|
|
2297
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2298
|
-
|
|
2299
|
-
with patch.object(service, "_discover_requirements", return_value=requirements):
|
|
2300
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2301
|
-
report = await service.check_completeness("88718940")
|
|
2302
|
-
|
|
2303
|
-
assert report.metrics.total_required == 3
|
|
2304
|
-
|
|
2305
|
-
@pytest.mark.asyncio
|
|
2306
|
-
async def test_check_completeness_validates_cache_entries(self):
|
|
2307
|
-
"""Should validate each requirement against cache."""
|
|
2308
|
-
state = _make_state_store()
|
|
2309
|
-
cache = _make_cache()
|
|
2310
|
-
service = MaterialCompletenessService(state, cache)
|
|
2311
|
-
|
|
2312
|
-
# Create 3 requirements with different identifiers
|
|
2313
|
-
requirements = [_make_requirement(identifier=f"page{i}") for i in range(3)]
|
|
2314
|
-
# All prepared
|
|
2315
|
-
_make_cache_entry(age_hours=2.0)
|
|
2316
|
-
|
|
2317
|
-
prepared_count = [0]
|
|
2318
|
-
|
|
2319
|
-
async def mock_validate(req, deep_check):
|
|
2320
|
-
prepared_count[0] += 1
|
|
2321
|
-
return {"status": "prepared", "entry": _make_prepared()}
|
|
2322
|
-
|
|
2323
|
-
with patch.object(service, "_discover_requirements", return_value=requirements):
|
|
2324
|
-
with patch.object(service, "_validate_requirement", side_effect=mock_validate):
|
|
2325
|
-
report = await service.check_completeness("88718940")
|
|
2326
|
-
|
|
2327
|
-
assert prepared_count[0] == 3
|
|
2328
|
-
assert report.metrics.total_prepared == 3
|
|
2329
|
-
|
|
2330
|
-
@pytest.mark.asyncio
|
|
2331
|
-
async def test_check_completeness_uses_requirement_key_for_deduplication(self):
|
|
2332
|
-
"""Should use requirement_key for deduplication."""
|
|
2333
|
-
state = _make_state_store()
|
|
2334
|
-
cache = _make_cache()
|
|
2335
|
-
service = MaterialCompletenessService(state, cache)
|
|
2336
|
-
|
|
2337
|
-
# Create duplicate requirements (same type, project, identifier)
|
|
2338
|
-
requirements = [
|
|
2339
|
-
_make_requirement(identifier="123", source="registry", priority=10),
|
|
2340
|
-
_make_requirement(identifier="123", source="checklist", priority=20),
|
|
2341
|
-
]
|
|
2342
|
-
|
|
2343
|
-
with patch.object(service, "_discover_requirements", return_value=requirements):
|
|
2344
|
-
# Mock validation to return prepared
|
|
2345
|
-
with patch.object(
|
|
2346
|
-
service, "_validate_requirement", return_value={"status": "prepared", "entry": _make_prepared()}
|
|
2347
|
-
):
|
|
2348
|
-
report = await service.check_completeness("88718940")
|
|
2349
|
-
|
|
2350
|
-
# Should only have one material since deduped
|
|
2351
|
-
total_materials = len(report.prepared) + len(report.missing) + len(report.stale)
|
|
2352
|
-
assert total_materials == 1
|
|
2353
|
-
|
|
2354
|
-
@pytest.mark.asyncio
|
|
2355
|
-
async def test_check_completeness_handles_missing_page_cache_dir(self):
|
|
2356
|
-
"""Should handle missing cache directory gracefully."""
|
|
2357
|
-
state = _make_state_store()
|
|
2358
|
-
# Use cache with non-existent directory
|
|
2359
|
-
cache = MaterialCache(cache_dir=Path("/nonexistent/cache"))
|
|
2360
|
-
service = MaterialCompletenessService(state, cache)
|
|
2361
|
-
|
|
2362
|
-
requirements = [_make_requirement()]
|
|
2363
|
-
|
|
2364
|
-
with patch.object(service, "_discover_requirements", return_value=requirements):
|
|
2365
|
-
report = await service.check_completeness("88718940")
|
|
2366
|
-
|
|
2367
|
-
# Should still generate report even with cache issues
|
|
2368
|
-
assert isinstance(report, CompletenessReport)
|
|
2369
|
-
|
|
2370
|
-
@pytest.mark.asyncio
|
|
2371
|
-
async def test_check_completeness_with_low_threshold_generates_deep_check_action(self):
|
|
2372
|
-
"""Should generate deep_check action when below threshold."""
|
|
2373
|
-
state = _make_state_store()
|
|
2374
|
-
cache = _make_cache()
|
|
2375
|
-
service = MaterialCompletenessService(state, cache)
|
|
2376
|
-
|
|
2377
|
-
# Create low completeness scenario
|
|
2378
|
-
requirements = [_make_requirement() for _ in range(10)]
|
|
2379
|
-
|
|
2380
|
-
with patch.object(service, "_discover_requirements", return_value=requirements):
|
|
2381
|
-
with patch.object(service.cache, "get_page_entry", return_value=None):
|
|
2382
|
-
report = await service.check_completeness("88718940", min_threshold_pct=90.0)
|
|
2383
|
-
|
|
2384
|
-
# Should have deep check action
|
|
2385
|
-
assert any(a.action_type == "deep_check" for a in report.actions)
|
|
2386
|
-
|
|
2387
|
-
@pytest.mark.asyncio
|
|
2388
|
-
async def test_check_completeness_above_threshold_no_deep_check(self):
|
|
2389
|
-
"""Should not generate deep_check action when above threshold."""
|
|
2390
|
-
state = _make_state_store()
|
|
2391
|
-
cache = _make_cache()
|
|
2392
|
-
service = MaterialCompletenessService(state, cache)
|
|
2393
|
-
|
|
2394
|
-
requirements = [_make_requirement() for _ in range(8)]
|
|
2395
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2396
|
-
|
|
2397
|
-
with patch.object(service, "_discover_requirements", return_value=requirements):
|
|
2398
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2399
|
-
report = await service.check_completeness("88718940", min_threshold_pct=80.0)
|
|
2400
|
-
|
|
2401
|
-
# Should not have deep check action since 8/10 = 80%
|
|
2402
|
-
deep_check_actions = [a for a in report.actions if a.action_type == "deep_check"]
|
|
2403
|
-
assert len(deep_check_actions) == 0
|
|
2404
|
-
|
|
2405
|
-
@pytest.mark.asyncio
|
|
2406
|
-
async def test_check_completeness_sets_checked_at_timestamp(self):
|
|
2407
|
-
"""Should set checked_at to current time."""
|
|
2408
|
-
state = _make_state_store()
|
|
2409
|
-
cache = _make_cache()
|
|
2410
|
-
service = MaterialCompletenessService(state, cache)
|
|
2411
|
-
|
|
2412
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2413
|
-
|
|
2414
|
-
before = datetime.now(UTC)
|
|
2415
|
-
|
|
2416
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2417
|
-
report = await service.check_completeness("88718940")
|
|
2418
|
-
|
|
2419
|
-
after = datetime.now(UTC)
|
|
2420
|
-
|
|
2421
|
-
assert before <= report.checked_at <= after
|
|
2422
|
-
|
|
2423
|
-
@pytest.mark.asyncio
|
|
2424
|
-
async def test_check_completeness_includes_project_key_in_report(self):
|
|
2425
|
-
"""Should include project_key in generated report."""
|
|
2426
|
-
state = _make_state_store()
|
|
2427
|
-
cache = _make_cache()
|
|
2428
|
-
service = MaterialCompletenessService(state, cache)
|
|
2429
|
-
|
|
2430
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2431
|
-
|
|
2432
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2433
|
-
report = await service.check_completeness("88718940")
|
|
2434
|
-
|
|
2435
|
-
assert report.project_key == "88718940"
|
|
2436
|
-
|
|
2437
|
-
@pytest.mark.asyncio
|
|
2438
|
-
async def test_check_completeness_preserves_explicit_requirements_priority(self):
|
|
2439
|
-
"""Should respect priority 200 for explicit requirements."""
|
|
2440
|
-
state = _make_state_store()
|
|
2441
|
-
cache = _make_cache()
|
|
2442
|
-
service = MaterialCompletenessService(state, cache)
|
|
2443
|
-
|
|
2444
|
-
# Explicit with priority 200
|
|
2445
|
-
explicit = [_make_requirement(priority=200)]
|
|
2446
|
-
|
|
2447
|
-
with patch.object(service, "_discover_requirements", return_value=explicit):
|
|
2448
|
-
with patch.object(
|
|
2449
|
-
service, "_validate_requirement", return_value={"status": "prepared", "entry": _make_prepared()}
|
|
2450
|
-
):
|
|
2451
|
-
report = await service.check_completeness("88718940", explicit_requirements=explicit)
|
|
2452
|
-
|
|
2453
|
-
# Should keep the explicit requirement
|
|
2454
|
-
assert report.metrics.total_required >= 1
|
|
2455
|
-
|
|
2456
|
-
@pytest.mark.asyncio
|
|
2457
|
-
async def test_check_completeness_handles_empty_project_links(self):
|
|
2458
|
-
"""Should handle project with no links gracefully."""
|
|
2459
|
-
state = _make_state_store(project_links=[])
|
|
2460
|
-
cache = _make_cache()
|
|
2461
|
-
service = MaterialCompletenessService(state, cache)
|
|
2462
|
-
|
|
2463
|
-
report = await service.check_completeness("88718940")
|
|
2464
|
-
|
|
2465
|
-
assert isinstance(report, CompletenessReport)
|
|
2466
|
-
|
|
2467
|
-
@pytest.mark.asyncio
|
|
2468
|
-
async def test_check_completeness_handles_empty_preparation(self):
|
|
2469
|
-
"""Should handle empty preparation gracefully."""
|
|
2470
|
-
state = _make_state_store(project_preparation={})
|
|
2471
|
-
cache = _make_cache()
|
|
2472
|
-
service = MaterialCompletenessService(state, cache)
|
|
2473
|
-
|
|
2474
|
-
report = await service.check_completeness("88718940")
|
|
2475
|
-
|
|
2476
|
-
assert isinstance(report, CompletenessReport)
|
|
2477
|
-
|
|
2478
|
-
@pytest.mark.asyncio
|
|
2479
|
-
async def test_check_completeness_includes_deep_check_in_report(self):
|
|
2480
|
-
"""Should include deep_check status in report."""
|
|
2481
|
-
state = _make_state_store()
|
|
2482
|
-
cache = _make_cache()
|
|
2483
|
-
service = MaterialCompletenessService(state, cache)
|
|
2484
|
-
|
|
2485
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2486
|
-
|
|
2487
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2488
|
-
report = await service.check_completeness("88718940", deep_check=True)
|
|
2489
|
-
|
|
2490
|
-
assert report.deep_checked is True
|
|
2491
|
-
|
|
2492
|
-
@pytest.mark.asyncio
|
|
2493
|
-
async def test_check_completeness_with_mixed_material_statuses(self):
|
|
2494
|
-
"""Should handle prepared, missing, and stale materials together."""
|
|
2495
|
-
state = _make_state_store()
|
|
2496
|
-
cache = _make_cache()
|
|
2497
|
-
service = MaterialCompletenessService(state, cache)
|
|
2498
|
-
|
|
2499
|
-
requirements = [
|
|
2500
|
-
_make_requirement(identifier="prepared"),
|
|
2501
|
-
_make_requirement(identifier="missing"),
|
|
2502
|
-
_make_requirement(identifier="stale"),
|
|
2503
|
-
]
|
|
2504
|
-
|
|
2505
|
-
async def mock_validate(req, deep_check):
|
|
2506
|
-
if req.identifier == "prepared":
|
|
2507
|
-
_make_cache_entry(age_hours=2.0)
|
|
2508
|
-
return {"status": "prepared", "entry": _make_prepared()}
|
|
2509
|
-
elif req.identifier == "missing":
|
|
2510
|
-
return {"status": "missing", "entry": _make_missing()}
|
|
2511
|
-
else: # stale
|
|
2512
|
-
return {"status": "stale", "entry": _make_stale()}
|
|
2513
|
-
|
|
2514
|
-
with patch.object(service, "_discover_requirements", return_value=requirements):
|
|
2515
|
-
with patch.object(service, "_validate_requirement", side_effect=mock_validate):
|
|
2516
|
-
report = await service.check_completeness("88718940")
|
|
2517
|
-
|
|
2518
|
-
assert len(report.prepared) >= 1
|
|
2519
|
-
assert len(report.missing) >= 1
|
|
2520
|
-
assert len(report.stale) >= 1
|
|
2521
|
-
|
|
2522
|
-
@pytest.mark.asyncio
|
|
2523
|
-
async def test_check_completeness_default_threshold(self):
|
|
2524
|
-
"""Should use default 80% threshold when not specified."""
|
|
2525
|
-
state = _make_state_store()
|
|
2526
|
-
cache = _make_cache()
|
|
2527
|
-
service = MaterialCompletenessService(state, cache)
|
|
2528
|
-
|
|
2529
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2530
|
-
|
|
2531
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2532
|
-
report = await service.check_completeness("88718940")
|
|
2533
|
-
|
|
2534
|
-
# Default threshold is 80
|
|
2535
|
-
assert report.get_readiness_status() == report.get_readiness_status(threshold_pct=80.0)
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
# ===========================================================================
|
|
2539
|
-
# Edge Cases and Error Handling
|
|
2540
|
-
# ===========================================================================
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
class TestEdgeCases:
|
|
2544
|
-
"""Tests for edge cases and error scenarios (15 tests)."""
|
|
2545
|
-
|
|
2546
|
-
@pytest.mark.asyncio
|
|
2547
|
-
async def test_handles_zero_requirements_gracefully(self):
|
|
2548
|
-
"""Should handle zero requirements without crashing."""
|
|
2549
|
-
state = _make_state_store()
|
|
2550
|
-
cache = _make_cache()
|
|
2551
|
-
service = MaterialCompletenessService(state, cache)
|
|
2552
|
-
|
|
2553
|
-
report = await service.check_completeness("88718940")
|
|
2554
|
-
|
|
2555
|
-
assert report.metrics.total_required == 0
|
|
2556
|
-
assert report.metrics.completeness_pct == 100.0
|
|
2557
|
-
|
|
2558
|
-
def test_requirement_key_handles_special_characters(self):
|
|
2559
|
-
"""Should handle special characters in identifiers."""
|
|
2560
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
2561
|
-
|
|
2562
|
-
req = _make_requirement(identifier="page-with-dashes", project_key="Project-With-Dashes")
|
|
2563
|
-
|
|
2564
|
-
key = service._requirement_key(req)
|
|
2565
|
-
|
|
2566
|
-
assert "page-with-dashes" in key
|
|
2567
|
-
assert "Project-With-Dashes" in key
|
|
2568
|
-
|
|
2569
|
-
def test_parse_requirement_dict_handles_missing_optional_fields(self):
|
|
2570
|
-
"""Should handle missing optional fields with defaults."""
|
|
2571
|
-
state = _make_state_store()
|
|
2572
|
-
cache = _make_cache()
|
|
2573
|
-
service = MaterialCompletenessService(state, cache)
|
|
2574
|
-
|
|
2575
|
-
data = {"material_type": "page", "identifier": "88718940"}
|
|
2576
|
-
|
|
2577
|
-
req = service._parse_requirement_dict(data, "CEP")
|
|
2578
|
-
|
|
2579
|
-
assert req.priority == 100 # default
|
|
2580
|
-
assert req.title is None
|
|
2581
|
-
assert req.metadata == {}
|
|
2582
|
-
|
|
2583
|
-
@pytest.mark.asyncio
|
|
2584
|
-
async def test_discover_requirements_merges_explicit_with_highest_priority(self):
|
|
2585
|
-
"""Explicit requirements should always have highest priority."""
|
|
2586
|
-
state = _make_state_store(
|
|
2587
|
-
project_links=[
|
|
2588
|
-
{"link_type": "confluence", "link_role": "page", "normalized_url": "http://c/p/123"},
|
|
2589
|
-
],
|
|
2590
|
-
)
|
|
2591
|
-
cache = _make_cache()
|
|
2592
|
-
service = MaterialCompletenessService(state, cache)
|
|
2593
|
-
|
|
2594
|
-
# Explicit with various priorities
|
|
2595
|
-
explicit_low = [_make_requirement(identifier="123", priority=1)]
|
|
2596
|
-
explicit_high = [_make_requirement(identifier="123", priority=300)]
|
|
2597
|
-
|
|
2598
|
-
# Pass both explicit requirements - should use highest priority
|
|
2599
|
-
requirements = await service._discover_requirements(
|
|
2600
|
-
"88718940", explicit_requirements=explicit_low + explicit_high
|
|
2601
|
-
)
|
|
2602
|
-
|
|
2603
|
-
# Should have used the higher priority (300)
|
|
2604
|
-
matching = [r for r in requirements if r.identifier == "123"]
|
|
2605
|
-
assert len(matching) == 1
|
|
2606
|
-
assert matching[0].priority == 300
|
|
2607
|
-
|
|
2608
|
-
@pytest.mark.asyncio
|
|
2609
|
-
async def test_validate_page_handles_cache_return_with_no_hashes(self):
|
|
2610
|
-
"""Should handle cache entry without hash information."""
|
|
2611
|
-
state = _make_state_store()
|
|
2612
|
-
cache = _make_cache()
|
|
2613
|
-
service = MaterialCompletenessService(state, cache)
|
|
2614
|
-
|
|
2615
|
-
req = _make_requirement(material_type=MaterialType.page)
|
|
2616
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2617
|
-
# No hash fields
|
|
2618
|
-
|
|
2619
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2620
|
-
result = await service._validate_page_requirement(req, deep_check=False)
|
|
2621
|
-
|
|
2622
|
-
assert result["status"] == "prepared"
|
|
2623
|
-
assert result["entry"].content_hash is None
|
|
2624
|
-
|
|
2625
|
-
@pytest.mark.asyncio
|
|
2626
|
-
async def test_generate_actions_empty_lists(self):
|
|
2627
|
-
"""Should handle empty material lists gracefully."""
|
|
2628
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
2629
|
-
|
|
2630
|
-
metrics = _make_metrics()
|
|
2631
|
-
actions = service._generate_actions(metrics, [], [], min_threshold_pct=80.0)
|
|
2632
|
-
|
|
2633
|
-
# Should have ignore action
|
|
2634
|
-
assert len(actions) == 1
|
|
2635
|
-
assert actions[0].action_type == "ignore"
|
|
2636
|
-
|
|
2637
|
-
def test_summarize_sources_counts_all_requirements(self):
|
|
2638
|
-
"""Should count all requirements regardless of other attributes."""
|
|
2639
|
-
service = MaterialCompletenessService(_make_state_store(), _make_cache())
|
|
2640
|
-
|
|
2641
|
-
requirements = [
|
|
2642
|
-
_make_requirement(source="registry", priority=10),
|
|
2643
|
-
_make_requirement(source="registry", priority=20),
|
|
2644
|
-
_make_requirement(source="checklist", priority=30),
|
|
2645
|
-
_make_requirement(source="explicit", priority=40),
|
|
2646
|
-
]
|
|
2647
|
-
|
|
2648
|
-
summary = service._summarize_sources(requirements)
|
|
2649
|
-
|
|
2650
|
-
assert summary["registry"] == 2
|
|
2651
|
-
assert summary["checklist"] == 1
|
|
2652
|
-
assert summary["explicit"] == 1
|
|
2653
|
-
|
|
2654
|
-
@pytest.mark.asyncio
|
|
2655
|
-
async def test_check_completeness_uses_cache_dir_for_diagnostics(self):
|
|
2656
|
-
"""Should include cache directory path in diagnostics."""
|
|
2657
|
-
state = _make_state_store()
|
|
2658
|
-
cache_dir = Path("/custom/cache")
|
|
2659
|
-
cache = MaterialCache(cache_dir=cache_dir)
|
|
2660
|
-
service = MaterialCompletenessService(state, cache)
|
|
2661
|
-
|
|
2662
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2663
|
-
|
|
2664
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2665
|
-
report = await service.check_completeness("88718940", cache_dir=cache_dir)
|
|
2666
|
-
|
|
2667
|
-
assert report.cache_dir == str(cache_dir)
|
|
2668
|
-
|
|
2669
|
-
@pytest.mark.asyncio
|
|
2670
|
-
async def test_check_completeness_preserves_requirement_metadata_in_report(self):
|
|
2671
|
-
"""Should preserve requirement metadata through to report."""
|
|
2672
|
-
state = _make_state_store()
|
|
2673
|
-
cache = _make_cache()
|
|
2674
|
-
service = MaterialCompletenessService(state, cache)
|
|
2675
|
-
|
|
2676
|
-
title = "Custom Page Title"
|
|
2677
|
-
requirements = [_make_requirement(title=title)]
|
|
2678
|
-
entry = _make_cache_entry(age_hours=2.0)
|
|
2679
|
-
|
|
2680
|
-
with patch.object(service, "_discover_requirements", return_value=requirements):
|
|
2681
|
-
with patch.object(service.cache, "get_page_entry", return_value=entry):
|
|
2682
|
-
report = await service.check_completeness("88718940")
|
|
2683
|
-
|
|
2684
|
-
assert len(report.prepared) >= 1
|
|
2685
|
-
# Title should be in prepared materials
|
|
2686
|
-
assert any(p.title == title for p in report.prepared)
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
# Additional helper functions for fixtures
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
def _make_prepared(**overrides: Any) -> PreparedMaterial:
|
|
2693
|
-
"""Create a PreparedMaterial for testing."""
|
|
2694
|
-
now = datetime.now(UTC)
|
|
2695
|
-
defaults = {
|
|
2696
|
-
"material_type": MaterialType.page,
|
|
2697
|
-
"identifier": "88718940",
|
|
2698
|
-
"project_key": "CEP",
|
|
2699
|
-
"title": "Test Page",
|
|
2700
|
-
"cached_at": now - timedelta(hours=2),
|
|
2701
|
-
"freshness": FreshnessTier.fresh,
|
|
2702
|
-
"last_accessed": now,
|
|
2703
|
-
"content_hash": "abc123",
|
|
2704
|
-
"age_hours": 2.0,
|
|
2705
|
-
}
|
|
2706
|
-
defaults.update(overrides)
|
|
2707
|
-
return PreparedMaterial(**defaults)
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
def _make_missing(**overrides: Any) -> MissingMaterial:
|
|
2711
|
-
"""Create a MissingMaterial for testing."""
|
|
2712
|
-
defaults = {
|
|
2713
|
-
"material_type": MaterialType.page,
|
|
2714
|
-
"identifier": "99999999",
|
|
2715
|
-
"project_key": "88718940",
|
|
2716
|
-
"reason": "not_in_cache",
|
|
2717
|
-
"title": "Missing Page",
|
|
2718
|
-
}
|
|
2719
|
-
defaults.update(overrides)
|
|
2720
|
-
return MissingMaterial(**defaults)
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
def _make_stale(**overrides: Any) -> StaleMaterial:
|
|
2724
|
-
"""Create a StaleMaterial for testing."""
|
|
2725
|
-
now = datetime.now(UTC)
|
|
2726
|
-
defaults = {
|
|
2727
|
-
"material_type": MaterialType.page,
|
|
2728
|
-
"identifier": "88888888",
|
|
2729
|
-
"project_key": "88718940",
|
|
2730
|
-
"stale_reason": "ttl_expired",
|
|
2731
|
-
"cached_at": now - timedelta(hours=50),
|
|
2732
|
-
"age_hours": 50.0,
|
|
2733
|
-
"recommended_action": "refresh",
|
|
2734
|
-
}
|
|
2735
|
-
defaults.update(overrides)
|
|
2736
|
-
return StaleMaterial(**defaults)
|