semantics

This commit is contained in:
2026-05-26 09:30:41 +03:00
parent 1e7bcecaea
commit 9ffa8af1dc
623 changed files with 28045 additions and 26557 deletions

View File

@@ -1,8 +1,8 @@
# [DEF:TestApprovalService:Module]
# @RELATION: BELONGS_TO -> SrcRoot
# #region TestApprovalService [C:2] [TYPE Module]
# @RELATION BINDS_TO -> SrcRoot
# @SEMANTICS: tests, clean-release, approval, lifecycle, gate
# @PURPOSE: Define approval gate contracts for approve/reject operations over immutable compliance evidence.
# @LAYER: Tests
# @LAYER Tests
# @INVARIANT: Approval is allowed only for PASSED report bound to candidate; duplicate approve and foreign report must be rejected.
from __future__ import annotations
@@ -17,8 +17,8 @@ from src.services.clean_release.exceptions import ApprovalGateError
from src.services.clean_release.repository import CleanReleaseRepository
# [DEF:_seed_candidate_with_report:Function]
# @RELATION: BINDS_TO -> TestApprovalService
# #region _seed_candidate_with_report [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestApprovalService
# @PURPOSE: Seed candidate and report fixtures for approval gate tests.
# @PRE: candidate_id and report_id are non-empty.
# @POST: Repository contains candidate and report linked by candidate_id.
@@ -55,11 +55,11 @@ def _seed_candidate_with_report(
)
)
return repository, candidate_id, report_id
# [/DEF:_seed_candidate_with_report:Function]
# #endregion _seed_candidate_with_report
# [DEF:test_approve_rejects_blocked_report:Function]
# @RELATION: BINDS_TO -> TestApprovalService
# #region test_approve_rejects_blocked_report [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestApprovalService
# @PURPOSE: Ensure approve is rejected when latest report final status is not PASSED.
# @PRE: Candidate has BLOCKED report.
# @POST: approve_candidate raises ApprovalGateError.
@@ -78,11 +78,11 @@ def test_approve_rejects_blocked_report():
decided_by="approver",
comment="blocked report cannot be approved",
)
# [/DEF:test_approve_rejects_blocked_report:Function]
# #endregion test_approve_rejects_blocked_report
# [DEF:test_approve_rejects_foreign_report:Function]
# @RELATION: BINDS_TO -> TestApprovalService
# #region test_approve_rejects_foreign_report [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestApprovalService
# @PURPOSE: Ensure approve is rejected when report belongs to another candidate.
# @PRE: Candidate exists, report candidate_id differs.
# @POST: approve_candidate raises ApprovalGateError.
@@ -109,11 +109,11 @@ def test_approve_rejects_foreign_report():
decided_by="approver",
comment="foreign report",
)
# [/DEF:test_approve_rejects_foreign_report:Function]
# #endregion test_approve_rejects_foreign_report
# [DEF:test_approve_rejects_duplicate_approve:Function]
# @RELATION: BINDS_TO -> TestApprovalService
# #region test_approve_rejects_duplicate_approve [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestApprovalService
# @PURPOSE: Ensure repeated approve decision for same candidate is blocked.
# @PRE: Candidate has already been approved once.
# @POST: Second approve_candidate call raises ApprovalGateError.
@@ -140,11 +140,11 @@ def test_approve_rejects_duplicate_approve():
decided_by="approver",
comment="duplicate approval",
)
# [/DEF:test_approve_rejects_duplicate_approve:Function]
# #endregion test_approve_rejects_duplicate_approve
# [DEF:test_reject_persists_decision_without_promoting_candidate_state:Function]
# @RELATION: BINDS_TO -> TestApprovalService
# #region test_reject_persists_decision_without_promoting_candidate_state [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestApprovalService
# @PURPOSE: Ensure reject decision is immutable and does not promote candidate to APPROVED.
# @PRE: Candidate has PASSED report and CHECK_PASSED lifecycle state.
# @POST: reject_candidate persists REJECTED decision; candidate status remains unchanged.
@@ -165,11 +165,11 @@ def test_reject_persists_decision_without_promoting_candidate_state():
assert decision.decision == ApprovalDecisionType.REJECTED.value
assert candidate is not None
assert candidate.status == CandidateStatus.CHECK_PASSED.value
# [/DEF:test_reject_persists_decision_without_promoting_candidate_state:Function]
# #endregion test_reject_persists_decision_without_promoting_candidate_state
# [DEF:test_reject_then_publish_is_blocked:Function]
# @RELATION: BINDS_TO -> TestApprovalService
# #region test_reject_then_publish_is_blocked [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestApprovalService
# @PURPOSE: Ensure latest REJECTED decision blocks publication gate.
# @PRE: Candidate is rejected for passed report.
# @POST: publish_candidate raises PublicationGateError.
@@ -197,6 +197,6 @@ def test_reject_then_publish_is_blocked():
target_channel="stable",
publication_ref="rel-blocked",
)
# [/DEF:test_reject_then_publish_is_blocked:Function]
# #endregion test_reject_then_publish_is_blocked
# [/DEF:TestApprovalService:Module]
# #endregion TestApprovalService

View File

@@ -1,7 +1,7 @@
# [DEF:test_candidate_manifest_services:Module]
# @RELATION: BELONGS_TO -> [SrcRoot:Module]
# #region test_candidate_manifest_services [C:2] [TYPE Module]
# @RELATION BINDS_TO -> [SrcRoot]
# @PURPOSE: Test lifecycle and manifest versioning for release candidates.
# @LAYER: Tests
# @LAYER Tests
from datetime import UTC, datetime
@@ -30,8 +30,8 @@ def db_session():
session.close()
# [DEF:test_candidate_lifecycle_transitions:Function]
# @RELATION: BINDS_TO -> [test_candidate_manifest_services:Module]
# #region test_candidate_lifecycle_transitions [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [test_candidate_manifest_services]
# @PURPOSE: Verify release candidate allows legal status transitions and rejects forbidden back-transitions.
def test_candidate_lifecycle_transitions(db_session):
"""
@@ -59,11 +59,11 @@ def test_candidate_lifecycle_transitions(db_session):
candidate.transition_to(CandidateStatus.DRAFT)
# [/DEF:test_candidate_lifecycle_transitions:Function]
# #endregion test_candidate_lifecycle_transitions
# [DEF:test_manifest_versioning_and_immutability:Function]
# @RELATION: BINDS_TO -> [test_candidate_manifest_services:Module]
# #region test_manifest_versioning_and_immutability [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [test_candidate_manifest_services]
# @PURPOSE: Verify manifest versions increment monotonically and older snapshots remain queryable.
def test_manifest_versioning_and_immutability(db_session):
"""
@@ -117,11 +117,11 @@ def test_manifest_versioning_and_immutability(db_session):
assert len(all_manifests) == 2
# [/DEF:test_manifest_versioning_and_immutability:Function]
# #endregion test_manifest_versioning_and_immutability
# [DEF:_valid_artifacts:Function]
# @RELATION: BINDS_TO -> [test_candidate_manifest_services:Module]
# #region _valid_artifacts [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [test_candidate_manifest_services]
# @PURPOSE: Provide canonical valid artifact payload used by candidate registration tests.
def _valid_artifacts():
return [
@@ -134,11 +134,11 @@ def _valid_artifacts():
]
# [/DEF:_valid_artifacts:Function]
# #endregion _valid_artifacts
# [DEF:test_register_candidate_rejects_duplicate_candidate_id:Function]
# @RELATION: BINDS_TO -> [test_candidate_manifest_services:Module]
# #region test_register_candidate_rejects_duplicate_candidate_id [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [test_candidate_manifest_services]
# @PURPOSE: Verify duplicate candidate_id registration is rejected by service invariants.
def test_register_candidate_rejects_duplicate_candidate_id():
repository = CleanReleaseRepository()
@@ -162,11 +162,11 @@ def test_register_candidate_rejects_duplicate_candidate_id():
)
# [/DEF:test_register_candidate_rejects_duplicate_candidate_id:Function]
# #endregion test_register_candidate_rejects_duplicate_candidate_id
# [DEF:test_register_candidate_rejects_malformed_artifact_input:Function]
# @RELATION: BINDS_TO -> [test_candidate_manifest_services:Module]
# #region test_register_candidate_rejects_malformed_artifact_input [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [test_candidate_manifest_services]
# @PURPOSE: Verify candidate registration rejects artifact payloads missing required fields.
def test_register_candidate_rejects_malformed_artifact_input():
repository = CleanReleaseRepository()
@@ -183,11 +183,11 @@ def test_register_candidate_rejects_malformed_artifact_input():
)
# [/DEF:test_register_candidate_rejects_malformed_artifact_input:Function]
# #endregion test_register_candidate_rejects_malformed_artifact_input
# [DEF:test_register_candidate_rejects_empty_artifact_set:Function]
# @RELATION: BINDS_TO -> [test_candidate_manifest_services:Module]
# #region test_register_candidate_rejects_empty_artifact_set [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [test_candidate_manifest_services]
# @PURPOSE: Verify candidate registration rejects empty artifact collections.
def test_register_candidate_rejects_empty_artifact_set():
repository = CleanReleaseRepository()
@@ -203,11 +203,11 @@ def test_register_candidate_rejects_empty_artifact_set():
)
# [/DEF:test_register_candidate_rejects_empty_artifact_set:Function]
# #endregion test_register_candidate_rejects_empty_artifact_set
# [DEF:test_manifest_service_rebuild_creates_new_version:Function]
# @RELATION: BINDS_TO -> [test_candidate_manifest_services:Module]
# #region test_manifest_service_rebuild_creates_new_version [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [test_candidate_manifest_services]
# @PURPOSE: Verify repeated manifest build creates a new incremented immutable version.
def test_manifest_service_rebuild_creates_new_version():
repository = CleanReleaseRepository()
@@ -232,11 +232,11 @@ def test_manifest_service_rebuild_creates_new_version():
assert first.id != second.id
# [/DEF:test_manifest_service_rebuild_creates_new_version:Function]
# #endregion test_manifest_service_rebuild_creates_new_version
# [DEF:test_manifest_service_existing_manifest_cannot_be_mutated:Function]
# @RELATION: BINDS_TO -> [test_candidate_manifest_services:Module]
# #region test_manifest_service_existing_manifest_cannot_be_mutated [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [test_candidate_manifest_services]
# @PURPOSE: Verify existing manifest snapshot remains immutable when rebuilding newer manifest version.
def test_manifest_service_existing_manifest_cannot_be_mutated():
repository = CleanReleaseRepository()
@@ -269,11 +269,11 @@ def test_manifest_service_existing_manifest_cannot_be_mutated():
assert rebuilt.id != created.id
# [/DEF:test_manifest_service_existing_manifest_cannot_be_mutated:Function]
# #endregion test_manifest_service_existing_manifest_cannot_be_mutated
# [DEF:test_manifest_service_rejects_missing_candidate:Function]
# @RELATION: BINDS_TO -> [test_candidate_manifest_services:Module]
# #region test_manifest_service_rejects_missing_candidate [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [test_candidate_manifest_services]
# @PURPOSE: Verify manifest build fails with missing candidate identifier.
def test_manifest_service_rejects_missing_candidate():
repository = CleanReleaseRepository()
@@ -286,5 +286,5 @@ def test_manifest_service_rejects_missing_candidate():
)
# [/DEF:test_manifest_service_rejects_missing_candidate:Function]
# [/DEF:test_candidate_manifest_services:Module]
# #endregion test_manifest_service_rejects_missing_candidate
# #endregion test_candidate_manifest_services

View File

@@ -1,8 +1,8 @@
# [DEF:TestComplianceExecutionService:Module]
# @RELATION: BELONGS_TO -> SrcRoot
# #region TestComplianceExecutionService [C:2] [TYPE Module]
# @RELATION BINDS_TO -> SrcRoot
# @SEMANTICS: tests, clean-release, compliance, pipeline, run-finalization
# @PURPOSE: Validate stage pipeline and run finalization contracts for compliance execution.
# @LAYER: Tests
# @LAYER Tests
# @INVARIANT: Missing manifest prevents run startup; failed execution cannot finalize as PASSED.
from __future__ import annotations
@@ -24,8 +24,8 @@ from src.services.clean_release.report_builder import ComplianceReportBuilder
from src.services.clean_release.repository import CleanReleaseRepository
# [DEF:_seed_with_candidate_policy_registry:Function]
# @RELATION: BINDS_TO -> TestComplianceExecutionService
# #region _seed_with_candidate_policy_registry [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestComplianceExecutionService
# @PURPOSE: Build deterministic repository state for run startup tests.
# @PRE: candidate_id and snapshot ids are non-empty.
# @POST: Returns repository with candidate, policy and registry; manifest is optional.
@@ -95,11 +95,11 @@ def _seed_with_candidate_policy_registry(
)
return repository, candidate_id, policy_id, manifest_id
# [/DEF:_seed_with_candidate_policy_registry:Function]
# #endregion _seed_with_candidate_policy_registry
# [DEF:test_run_without_manifest_rejected:Function]
# @RELATION: BINDS_TO -> TestComplianceExecutionService
# #region test_run_without_manifest_rejected [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestComplianceExecutionService
# @PURPOSE: Ensure compliance run cannot start when manifest is unresolved.
# @PRE: Candidate/policy exist but manifest is missing.
# @POST: start_check_run raises ValueError and no run is persisted.
@@ -116,11 +116,11 @@ def test_run_without_manifest_rejected():
)
assert len(repository.check_runs) == 0
# [/DEF:test_run_without_manifest_rejected:Function]
# #endregion test_run_without_manifest_rejected
# [DEF:test_task_crash_mid_run_marks_failed:Function]
# @RELATION: BINDS_TO -> TestComplianceExecutionService
# #region test_task_crash_mid_run_marks_failed [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestComplianceExecutionService
# @PURPOSE: Ensure execution crash conditions force FAILED run status.
# @PRE: Run exists, then required dependency becomes unavailable before execute_stages.
# @POST: execute_stages persists run with FAILED status.
@@ -140,11 +140,11 @@ def test_task_crash_mid_run_marks_failed():
failed = orchestrator.execute_stages(run)
assert failed.status == RunStatus.FAILED
# [/DEF:test_task_crash_mid_run_marks_failed:Function]
# #endregion test_task_crash_mid_run_marks_failed
# [DEF:test_blocked_run_finalization_blocks_report_builder:Function]
# @RELATION: BINDS_TO -> TestComplianceExecutionService
# #region test_blocked_run_finalization_blocks_report_builder [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestComplianceExecutionService
# @PURPOSE: Ensure blocked runs require blocking violations before report creation.
# @PRE: Manifest contains prohibited artifacts leading to BLOCKED decision.
# @POST: finalize keeps BLOCKED and report_builder rejects zero blocking violations.
@@ -170,6 +170,6 @@ def test_blocked_run_finalization_blocks_report_builder():
with pytest.raises(ValueError, match="Blocked run requires at least one blocking violation"):
builder.build_report_payload(run, [])
# [/DEF:test_blocked_run_finalization_blocks_report_builder:Function]
# #endregion test_blocked_run_finalization_blocks_report_builder
# [/DEF:TestComplianceExecutionService:Module]
# #endregion TestComplianceExecutionService

View File

@@ -1,8 +1,8 @@
# [DEF:TestComplianceTaskIntegration:Module]
# @RELATION: BELONGS_TO -> SrcRoot
# #region TestComplianceTaskIntegration [C:2] [TYPE Module]
# @RELATION BINDS_TO -> SrcRoot
# @SEMANTICS: tests, clean-release, compliance, task-manager, integration
# @PURPOSE: Verify clean release compliance runs execute through TaskManager lifecycle with observable success/failure outcomes.
# @LAYER: Tests
# @LAYER Tests
# @INVARIANT: Compliance execution triggered as task produces terminal task status and persists run evidence.
from __future__ import annotations
@@ -29,8 +29,8 @@ from src.services.clean_release.enums import CandidateStatus, RunStatus
from src.services.clean_release.repository import CleanReleaseRepository
# [DEF:_seed_repository:Function]
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
# #region _seed_repository [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestComplianceTaskIntegration
# @PURPOSE: Prepare deterministic candidate/policy/registry/manifest fixtures for task integration tests.
# @PRE: with_manifest controls manifest availability.
# @POST: Returns initialized repository and identifiers for compliance run startup.
@@ -99,11 +99,11 @@ def _seed_repository(
return repository, candidate_id, policy_id, manifest_id
# [/DEF:_seed_repository:Function]
# #endregion _seed_repository
# [DEF:CleanReleaseCompliancePlugin:Class]
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
# #region CleanReleaseCompliancePlugin [C:2] [TYPE Class]
# @RELATION BINDS_TO -> TestComplianceTaskIntegration
# @PURPOSE: TaskManager plugin shim that executes clean release compliance orchestration.
class CleanReleaseCompliancePlugin:
@property
@@ -138,11 +138,11 @@ class CleanReleaseCompliancePlugin:
}
# [/DEF:CleanReleaseCompliancePlugin:Class]
# #endregion CleanReleaseCompliancePlugin
# [DEF:_PluginLoaderStub:Class]
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
# #region _PluginLoaderStub [C:2] [TYPE Class]
# @RELATION BINDS_TO -> TestComplianceTaskIntegration
# @PURPOSE: Provide minimal plugin loader contract used by TaskManager in integration tests.
# @INVARIANT: has_plugin/get_plugin only acknowledge the seeded compliance plugin id.
class _PluginLoaderStub:
@@ -174,11 +174,11 @@ class _PluginLoaderStub:
)
# [/DEF:_PluginLoaderStub:Class]
# #endregion _PluginLoaderStub
# [DEF:_make_task_manager:Function]
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
# #region _make_task_manager [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestComplianceTaskIntegration
# @PURPOSE: Build TaskManager with mocked persistence services for isolated integration tests.
# @POST: Returns TaskManager ready for async task execution.
def _make_task_manager() -> TaskManager:
@@ -202,11 +202,11 @@ def _make_task_manager() -> TaskManager:
return TaskManager(plugin_loader)
# [/DEF:_make_task_manager:Function]
# #endregion _make_task_manager
# [DEF:_wait_for_terminal_task:Function]
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
# #region _wait_for_terminal_task [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestComplianceTaskIntegration
# @PURPOSE: Poll task registry until target task reaches terminal status.
# @PRE: task_id exists in manager registry.
# @POST: Returns task with SUCCESS or FAILED status, otherwise raises TimeoutError.
@@ -223,11 +223,11 @@ async def _wait_for_terminal_task(
await asyncio.sleep(0.05)
# [/DEF:_wait_for_terminal_task:Function]
# #endregion _wait_for_terminal_task
# [DEF:test_compliance_run_executes_as_task_manager_task:Function]
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
# #region test_compliance_run_executes_as_task_manager_task [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestComplianceTaskIntegration
# @PURPOSE: Verify successful compliance execution is observable as TaskManager SUCCESS task.
# @PRE: Candidate, policy and manifest are available in repository.
# @POST: Task ends with SUCCESS; run is persisted with SUCCEEDED status and task binding.
@@ -264,11 +264,11 @@ async def test_compliance_run_executes_as_task_manager_task():
manager._flusher_thread.join(timeout=2)
# [/DEF:test_compliance_run_executes_as_task_manager_task:Function]
# #endregion test_compliance_run_executes_as_task_manager_task
# [DEF:test_compliance_run_missing_manifest_marks_task_failed:Function]
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
# #region test_compliance_run_missing_manifest_marks_task_failed [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestComplianceTaskIntegration
# @PURPOSE: Verify missing manifest startup failure is surfaced as TaskManager FAILED task.
# @PRE: Candidate/policy exist but manifest is absent.
# @POST: Task ends with FAILED and run history remains empty.
@@ -302,6 +302,6 @@ async def test_compliance_run_missing_manifest_marks_task_failed():
manager._flusher_thread.join(timeout=2)
# [/DEF:test_compliance_run_missing_manifest_marks_task_failed:Function]
# #endregion test_compliance_run_missing_manifest_marks_task_failed
# [/DEF:TestComplianceTaskIntegration:Module]
# #endregion TestComplianceTaskIntegration

View File

@@ -1,8 +1,8 @@
# [DEF:TestDemoModeIsolation:Module]
# #region TestDemoModeIsolation [C:2] [TYPE Module]
# @SEMANTICS: clean-release, demo-mode, isolation, namespace, repository
# @PURPOSE: Verify demo and real mode namespace isolation contracts before TUI integration.
# @LAYER: Tests
# @RELATION: DEPENDS_ON -> backend.src.services.clean_release.demo_data_service
# @LAYER Tests
# @RELATION DEPENDS_ON -> [EXT:path:backend.src.services.clean_release.demo_data_service]
from __future__ import annotations
@@ -16,8 +16,8 @@ from src.services.clean_release.demo_data_service import (
)
# [DEF:test_resolve_namespace_separates_demo_and_real:Function]
# @RELATION: BINDS_TO -> TestDemoModeIsolation
# #region test_resolve_namespace_separates_demo_and_real [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestDemoModeIsolation
# @PURPOSE: Ensure namespace resolver returns deterministic and distinct namespaces.
# @PRE: Mode names are provided as user/runtime strings.
# @POST: Demo and real namespaces are different and stable.
@@ -28,11 +28,11 @@ def test_resolve_namespace_separates_demo_and_real() -> None:
assert demo == "clean-release:demo"
assert real == "clean-release:real"
assert demo != real
# [/DEF:test_resolve_namespace_separates_demo_and_real:Function]
# #endregion test_resolve_namespace_separates_demo_and_real
# [DEF:test_build_namespaced_id_prevents_cross_mode_collisions:Function]
# @RELATION: BINDS_TO -> TestDemoModeIsolation
# #region test_build_namespaced_id_prevents_cross_mode_collisions [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestDemoModeIsolation
# @PURPOSE: Ensure ID generation prevents demo/real collisions for identical logical IDs.
# @PRE: Same logical candidate id is used in two different namespaces.
# @POST: Produced physical IDs differ by namespace prefix.
@@ -44,11 +44,11 @@ def test_build_namespaced_id_prevents_cross_mode_collisions() -> None:
assert demo_id != real_id
assert demo_id.startswith("clean-release:demo::")
assert real_id.startswith("clean-release:real::")
# [/DEF:test_build_namespaced_id_prevents_cross_mode_collisions:Function]
# #endregion test_build_namespaced_id_prevents_cross_mode_collisions
# [DEF:test_create_isolated_repository_keeps_mode_data_separate:Function]
# @RELATION: BINDS_TO -> TestDemoModeIsolation
# #region test_create_isolated_repository_keeps_mode_data_separate [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestDemoModeIsolation
# @PURPOSE: Verify demo and real repositories do not leak state across mode boundaries.
# @PRE: Two repositories are created for distinct modes.
# @POST: Candidate mutations in one mode are not visible in the other mode.
@@ -84,6 +84,6 @@ def test_create_isolated_repository_keeps_mode_data_separate() -> None:
assert demo_repo.get_candidate(real_candidate_id) is None
assert real_repo.get_candidate(real_candidate_id) is not None
assert real_repo.get_candidate(demo_candidate_id) is None
# [/DEF:test_create_isolated_repository_keeps_mode_data_separate:Function]
# #endregion test_create_isolated_repository_keeps_mode_data_separate
# [/DEF:TestDemoModeIsolation:Module]
# #endregion TestDemoModeIsolation

View File

@@ -1,10 +1,10 @@
# [DEF:TestPolicyResolutionService:Module]
# #region TestPolicyResolutionService [C:2] [TYPE Module]
# @SEMANTICS: clean-release, policy-resolution, trusted-snapshots, contracts
# @PURPOSE: Verify trusted policy snapshot resolution contract and error guards.
# @LAYER: Tests
# @RELATION: DEPENDS_ON -> [policy_resolution_service]
# @RELATION: DEPENDS_ON -> [repository]
# @RELATION: DEPENDS_ON -> [clean_release_exceptions]
# @LAYER Tests
# @RELATION DEPENDS_ON -> [EXT:frontend:policy_resolution_service]
# @RELATION DEPENDS_ON -> [EXT:frontend:repository]
# @RELATION DEPENDS_ON -> [clean_release_exceptions]
# @INVARIANT: Resolution uses only ConfigManager active IDs and rejects runtime override attempts.
from __future__ import annotations
@@ -21,8 +21,8 @@ from src.services.clean_release.policy_resolution_service import (
from src.services.clean_release.repository import CleanReleaseRepository
# [DEF:_config_manager:Function]
# @RELATION: BINDS_TO -> [TestPolicyResolutionService]
# #region _config_manager [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [EXT:frontend:TestPolicyResolutionService]
# @PURPOSE: Build deterministic ConfigManager-like stub for tests.
# @INVARIANT: Only settings.clean_release.active_policy_id and active_registry_id are populated; any other settings field access raises AttributeError.
# @PRE: policy_id and registry_id may be None or non-empty strings.
@@ -36,11 +36,11 @@ def _config_manager(policy_id, registry_id):
return SimpleNamespace(get_config=lambda: config)
# [/DEF:_config_manager:Function]
# #endregion _config_manager
# [DEF:test_resolve_trusted_policy_snapshots_missing_profile:Function]
# @RELATION: BINDS_TO -> [TestPolicyResolutionService]
# #region test_resolve_trusted_policy_snapshots_missing_profile [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [EXT:frontend:TestPolicyResolutionService]
# @PURPOSE: Ensure resolution fails when trusted profile is not configured.
# @PRE: active_policy_id is None.
# @POST: Raises PolicyResolutionError with missing trusted profile reason.
@@ -55,11 +55,11 @@ def test_resolve_trusted_policy_snapshots_missing_profile():
)
# [/DEF:test_resolve_trusted_policy_snapshots_missing_profile:Function]
# #endregion test_resolve_trusted_policy_snapshots_missing_profile
# [DEF:test_resolve_trusted_policy_snapshots_missing_registry:Function]
# @RELATION: BINDS_TO -> [TestPolicyResolutionService]
# #region test_resolve_trusted_policy_snapshots_missing_registry [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [EXT:frontend:TestPolicyResolutionService]
# @PURPOSE: Ensure resolution fails when trusted registry is not configured.
# @PRE: active_registry_id is None and active_policy_id is set.
# @POST: Raises PolicyResolutionError with missing trusted registry reason.
@@ -74,11 +74,11 @@ def test_resolve_trusted_policy_snapshots_missing_registry():
)
# [/DEF:test_resolve_trusted_policy_snapshots_missing_registry:Function]
# #endregion test_resolve_trusted_policy_snapshots_missing_registry
# [DEF:test_resolve_trusted_policy_snapshots_rejects_override_attempt:Function]
# @RELATION: BINDS_TO -> [TestPolicyResolutionService]
# #region test_resolve_trusted_policy_snapshots_rejects_override_attempt [C:2] [TYPE Function]
# @RELATION BINDS_TO -> [EXT:frontend:TestPolicyResolutionService]
# @PURPOSE: Ensure runtime override attempt is rejected even if snapshots exist.
# @PRE: valid trusted snapshots exist in repository and override is provided.
# @POST: Raises PolicyResolutionError with override forbidden reason.
@@ -116,6 +116,6 @@ def test_resolve_trusted_policy_snapshots_rejects_override_attempt():
)
# [/DEF:test_resolve_trusted_policy_snapshots_rejects_override_attempt:Function]
# #endregion test_resolve_trusted_policy_snapshots_rejects_override_attempt
# [/DEF:TestPolicyResolutionService:Module]
# #endregion TestPolicyResolutionService

View File

@@ -1,8 +1,8 @@
# [DEF:TestPublicationService:Module]
# @RELATION: BELONGS_TO -> SrcRoot
# #region TestPublicationService [C:2] [TYPE Module]
# @RELATION BINDS_TO -> SrcRoot
# @SEMANTICS: tests, clean-release, publication, revoke, gate
# @PURPOSE: Define publication gate contracts over approved candidates and immutable publication records.
# @LAYER: Tests
# @LAYER Tests
# @INVARIANT: Publish requires approval; revoke requires existing publication; republish after revoke is allowed as a new record.
from __future__ import annotations
@@ -17,8 +17,8 @@ from src.services.clean_release.exceptions import PublicationGateError
from src.services.clean_release.repository import CleanReleaseRepository
# [DEF:_seed_candidate_with_passed_report:Function]
# @RELATION: BINDS_TO -> TestPublicationService
# #region _seed_candidate_with_passed_report [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestPublicationService
# @PURPOSE: Seed candidate/report fixtures for publication gate scenarios.
# @PRE: candidate_id and report_id are non-empty.
# @POST: Repository contains candidate and PASSED report.
@@ -51,11 +51,11 @@ def _seed_candidate_with_passed_report(
)
)
return repository, candidate_id, report_id
# [/DEF:_seed_candidate_with_passed_report:Function]
# #endregion _seed_candidate_with_passed_report
# [DEF:test_publish_without_approval_rejected:Function]
# @RELATION: BINDS_TO -> TestPublicationService
# #region test_publish_without_approval_rejected [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestPublicationService
# @PURPOSE: Ensure publish action is blocked until candidate is approved.
# @PRE: Candidate has PASSED report but status is not APPROVED.
# @POST: publish_candidate raises PublicationGateError.
@@ -75,11 +75,11 @@ def test_publish_without_approval_rejected():
target_channel="stable",
publication_ref="rel-1",
)
# [/DEF:test_publish_without_approval_rejected:Function]
# #endregion test_publish_without_approval_rejected
# [DEF:test_revoke_unknown_publication_rejected:Function]
# @RELATION: BINDS_TO -> TestPublicationService
# #region test_revoke_unknown_publication_rejected [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestPublicationService
# @PURPOSE: Ensure revocation is rejected for unknown publication id.
# @PRE: Repository has no matching publication record.
# @POST: revoke_publication raises PublicationGateError.
@@ -95,11 +95,11 @@ def test_revoke_unknown_publication_rejected():
revoked_by="publisher",
comment="unknown publication id",
)
# [/DEF:test_revoke_unknown_publication_rejected:Function]
# #endregion test_revoke_unknown_publication_rejected
# [DEF:test_republish_after_revoke_creates_new_active_record:Function]
# @RELATION: BINDS_TO -> TestPublicationService
# #region test_republish_after_revoke_creates_new_active_record [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestPublicationService
# @PURPOSE: Ensure republish after revoke is allowed and creates a new ACTIVE record.
# @PRE: Candidate is APPROVED and first publication has been revoked.
# @POST: New publish call returns distinct publication id with ACTIVE status.
@@ -144,6 +144,6 @@ def test_republish_after_revoke_creates_new_active_record():
assert first.id != second.id
assert revoked.status == PublicationStatus.REVOKED.value
assert second.status == PublicationStatus.ACTIVE.value
# [/DEF:test_republish_after_revoke_creates_new_active_record:Function]
# #endregion test_republish_after_revoke_creates_new_active_record
# [/DEF:TestPublicationService:Module]
# #endregion TestPublicationService

View File

@@ -1,8 +1,8 @@
# [DEF:TestReportAuditImmutability:Module]
# @RELATION: BELONGS_TO -> SrcRoot
# #region TestReportAuditImmutability [C:2] [TYPE Module]
# @RELATION BINDS_TO -> SrcRoot
# @SEMANTICS: tests, clean-release, report, audit, immutability, append-only
# @PURPOSE: Validate report snapshot immutability expectations and append-only audit hook behavior for US2.
# @LAYER: Tests
# @LAYER Tests
# @INVARIANT: Built reports are immutable snapshots; audit hooks produce append-only event traces.
from __future__ import annotations
@@ -26,8 +26,8 @@ from src.services.clean_release.report_builder import ComplianceReportBuilder
from src.services.clean_release.repository import CleanReleaseRepository
# [DEF:_terminal_run:Function]
# @RELATION: BINDS_TO -> TestReportAuditImmutability
# #region _terminal_run [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestReportAuditImmutability
# @PURPOSE: Build deterministic terminal run fixture for report snapshot tests.
# @PRE: final_status is a valid ComplianceDecision value.
# @POST: Returns a terminal ComplianceRun suitable for report generation.
@@ -50,11 +50,11 @@ def _terminal_run(
)
# [/DEF:_terminal_run:Function]
# #endregion _terminal_run
# [DEF:test_report_builder_sets_immutable_snapshot_flag:Function]
# @RELATION: BINDS_TO -> TestReportAuditImmutability
# #region test_report_builder_sets_immutable_snapshot_flag [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestReportAuditImmutability
# @PURPOSE: Ensure generated report payload is marked immutable and persisted as snapshot.
# @PRE: Terminal run exists.
# @POST: Built report has immutable=True and repository stores same immutable object.
@@ -71,11 +71,11 @@ def test_report_builder_sets_immutable_snapshot_flag():
assert repository.get_report(report.id) is persisted
# [/DEF:test_report_builder_sets_immutable_snapshot_flag:Function]
# #endregion test_report_builder_sets_immutable_snapshot_flag
# [DEF:test_repository_rejects_report_overwrite_for_same_report_id:Function]
# @RELATION: BINDS_TO -> TestReportAuditImmutability
# #region test_repository_rejects_report_overwrite_for_same_report_id [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestReportAuditImmutability
# @PURPOSE: Define immutability contract that report snapshots cannot be overwritten by same identifier.
# @PRE: Existing report with id is already persisted.
# @POST: Second save for same report id is rejected with explicit immutability error.
@@ -114,11 +114,11 @@ def test_repository_rejects_report_overwrite_for_same_report_id():
repository.save_report(mutated)
# [/DEF:test_repository_rejects_report_overwrite_for_same_report_id:Function]
# #endregion test_repository_rejects_report_overwrite_for_same_report_id
# [DEF:test_audit_hooks_emit_append_only_event_stream:Function]
# @RELATION: BINDS_TO -> TestReportAuditImmutability
# #region test_audit_hooks_emit_append_only_event_stream [C:2] [TYPE Function]
# @RELATION BINDS_TO -> TestReportAuditImmutability
# @PURPOSE: Verify audit hooks emit one event per action call and preserve call order.
# @PRE: Logger backend is patched.
# @POST: Three calls produce three ordered info entries with molecular prefixes.
@@ -141,6 +141,6 @@ def test_audit_hooks_emit_append_only_event_stream(mock_logger):
assert explore_msg.startswith("clean-release report_id")
# [/DEF:test_audit_hooks_emit_append_only_event_stream:Function]
# #endregion test_audit_hooks_emit_append_only_event_stream
# [/DEF:TestReportAuditImmutability:Module]
# #endregion TestReportAuditImmutability

View File

@@ -1,9 +1,9 @@
# [DEF:SupersetCompatibilityMatrixTests:Module]
# #region SupersetCompatibilityMatrixTests [C:2] [TYPE Module]
# @SEMANTICS: dataset_review, superset, compatibility_matrix, preview, sql_lab, tests
# @PURPOSE: Verifies Superset preview and SQL Lab endpoint fallback strategy used by dataset-review orchestration.
# @LAYER: Tests
# @RELATION: [DEPENDS_ON] ->[backend.src.core.superset_client.SupersetClient]
# @RELATION: [DEPENDS_ON] ->[SupersetCompilationAdapter]
# @LAYER Tests
# @RELATION DEPENDS_ON ->[SupersetClient]
# @RELATION DEPENDS_ON ->[SupersetCompilationAdapter]
from types import SimpleNamespace
from unittest.mock import MagicMock
@@ -17,9 +17,9 @@ from src.core.utils.superset_compilation_adapter import (
# Import models to ensure proper SQLAlchemy registration
# [DEF:make_adapter:Function]
# #region make_adapter [C:2] [TYPE Function]
# @PURPOSE: Build an adapter with a mock Superset client and deterministic environment for compatibility tests.
# @RELATION: [DEPENDS_ON] ->[SupersetCompilationAdapter]
# @RELATION DEPENDS_ON ->[SupersetCompilationAdapter]
def make_adapter():
environment = SimpleNamespace(
id="env-1",
@@ -35,12 +35,12 @@ def make_adapter():
return SupersetCompilationAdapter(environment=environment, client=client), client
# [/DEF:make_adapter:Function]
# #endregion make_adapter
# [DEF:test_preview_prefers_supported_client_method_before_network_fallback:Function]
# #region test_preview_prefers_supported_client_method_before_network_fallback [C:2] [TYPE Function]
# @PURPOSE: Confirms preview compilation uses a supported client method first when the capability exists.
# @RELATION: [DEPENDS_ON] ->[SupersetCompilationAdapter]
# @RELATION DEPENDS_ON ->[SupersetCompilationAdapter]
def test_preview_prefers_supported_client_method_before_network_fallback():
adapter, client = make_adapter()
client.compile_preview = MagicMock(return_value={"compiled_sql": "SELECT 1"})
@@ -60,12 +60,12 @@ def test_preview_prefers_supported_client_method_before_network_fallback():
client.network.request.assert_not_called()
# [/DEF:test_preview_prefers_supported_client_method_before_network_fallback:Function]
# #endregion test_preview_prefers_supported_client_method_before_network_fallback
# [DEF:test_preview_falls_back_across_matrix_until_supported_endpoint_returns_sql:Function]
# #region test_preview_falls_back_across_matrix_until_supported_endpoint_returns_sql [C:2] [TYPE Function]
# @PURPOSE: Confirms preview fallback walks the compatibility matrix from preferred to legacy endpoints until one returns compiled SQL.
# @RELATION: [DEPENDS_ON] ->[SupersetCompilationAdapter]
# @RELATION DEPENDS_ON ->[SupersetCompilationAdapter]
def test_preview_falls_back_across_matrix_until_supported_endpoint_returns_sql():
adapter, client = make_adapter()
payload = PreviewCompilationPayload(
@@ -94,12 +94,12 @@ def test_preview_falls_back_across_matrix_until_supported_endpoint_returns_sql()
assert second_call["endpoint"] == "/dataset/77/sql"
# [/DEF:test_preview_falls_back_across_matrix_until_supported_endpoint_returns_sql:Function]
# #endregion test_preview_falls_back_across_matrix_until_supported_endpoint_returns_sql
# [DEF:test_sql_lab_launch_falls_back_to_legacy_execute_endpoint:Function]
# #region test_sql_lab_launch_falls_back_to_legacy_execute_endpoint [C:2] [TYPE Function]
# @PURPOSE: Confirms SQL Lab launch falls back from modern to legacy execute endpoint and preserves canonical session reference extraction.
# @RELATION: [DEPENDS_ON] ->[SupersetCompilationAdapter]
# @RELATION DEPENDS_ON ->[SupersetCompilationAdapter]
def test_sql_lab_launch_falls_back_to_legacy_execute_endpoint():
adapter, client = make_adapter()
client.get_dataset.return_value = {
@@ -133,7 +133,7 @@ def test_sql_lab_launch_falls_back_to_legacy_execute_endpoint():
assert second_call["endpoint"] == "/sql_lab/execute/"
# [/DEF:test_sql_lab_launch_falls_back_to_legacy_execute_endpoint:Function]
# #endregion test_sql_lab_launch_falls_back_to_legacy_execute_endpoint
# [/DEF:SupersetCompatibilityMatrixTests:Module]
# #endregion SupersetCompatibilityMatrixTests