semantics

This commit is contained in:
2026-04-02 12:12:23 +03:00
parent ea457c8d18
commit c6147385e5
15 changed files with 138 additions and 312 deletions

View File

@@ -6,7 +6,7 @@ os.environ["ENCRYPTION_KEY"] = "OnrCzomBWbIjTf7Y-fnhL2adlU55bHZQjp8zX5zBC5w="
# @SEMANTICS: tests, assistant, authz, confirmation, rbac
# @PURPOSE: Verify assistant confirmation ownership, expiration, and deny behavior for restricted users.
# @LAYER: UI (API Tests)
# @RELATION: DEPENDS_ON -> backend.src.api.routes.assistant
# @RELATION: DEPENDS_ON -> AssistantApi
# @INVARIANT: Security-sensitive flows fail closed for unauthorized actors.

View File

@@ -3,7 +3,7 @@
# @SEMANTICS: datasets, api, tests, pagination, mapping, docs
# @PURPOSE: Unit tests for datasets API endpoints.
# @LAYER: API
# @RELATION: DEPENDS_ON -> [src.api.routes.datasets:Module]
# @RELATION: DEPENDS_ON -> [DatasetsApi]
# @INVARIANT: Endpoint contracts remain stable for success and validation failure paths.
import pytest

View File

@@ -1456,38 +1456,18 @@ async def export_validation(session_id: str, format: ArtifactFormat=Query(Artifa
# @POST: Returns at most one active clarification question with why_it_matters, current_guess, and ordered options; sessions without a clarification record return a non-blocking empty state.
# @SIDE_EFFECT: May normalize clarification pointer and readiness state in persistence.
# @DATA_CONTRACT: Input[session_id:str] -> Output[ClarificationStateResponse]
@router.get(
"/sessions/{session_id}/clarification",
response_model=ClarificationStateResponse,
dependencies=[
Depends(_require_auto_review_flag),
Depends(_require_clarification_flag),
Depends(has_permission("dataset:session", "READ")),
],
)
async def get_clarification_state(
session_id: str,
repository: DatasetReviewSessionRepository = Depends(_get_repository),
clarification_engine: ClarificationEngine = Depends(_get_clarification_engine),
current_user: User = Depends(get_current_user),
):
with belief_scope("dataset_review.get_clarification_state"):
@router.get('/sessions/{session_id}/clarification', response_model=ClarificationStateResponse, dependencies=[Depends(_require_auto_review_flag), Depends(_require_clarification_flag), Depends(has_permission('dataset:session', 'READ'))])
async def get_clarification_state(session_id: str, repository: DatasetReviewSessionRepository=Depends(_get_repository), clarification_engine: ClarificationEngine=Depends(_get_clarification_engine), current_user: User=Depends(get_current_user)):
with belief_scope('get_clarification_state'):
logger.reason('Belief protocol reasoning checkpoint for get_clarification_state')
session = _get_owned_session_or_404(repository, session_id, current_user)
if not session.clarification_sessions:
logger.reflect('Belief protocol postcondition checkpoint for get_clarification_state')
return _serialize_empty_clarification_state()
clarification_session = _get_latest_clarification_session_or_404(session)
current_question = clarification_engine.build_question_payload(session)
return _serialize_clarification_state(
ClarificationStateResult(
clarification_session=clarification_session,
current_question=current_question,
session=session,
changed_findings=[],
)
)
logger.reflect('Belief protocol postcondition checkpoint for get_clarification_state')
return _serialize_clarification_state(ClarificationStateResult(clarification_session=clarification_session, current_question=current_question, session=session, changed_findings=[]))
# [/DEF:get_clarification_state:Function]
@@ -1499,38 +1479,15 @@ async def get_clarification_state(
# @POST: Clarification session enters active state with one current question or completes deterministically when no unresolved items remain.
# @SIDE_EFFECT: Mutates clarification pointer, readiness, and recommended action.
# @DATA_CONTRACT: Input[session_id:str] -> Output[ClarificationStateResponse]
@router.post(
"/sessions/{session_id}/clarification/resume",
response_model=ClarificationStateResponse,
dependencies=[
Depends(_require_auto_review_flag),
Depends(_require_clarification_flag),
Depends(has_permission("dataset:session", "MANAGE")),
],
)
async def resume_clarification(
session_id: str,
session_version: int = Depends(_require_session_version_header),
repository: DatasetReviewSessionRepository = Depends(_get_repository),
clarification_engine: ClarificationEngine = Depends(_get_clarification_engine),
current_user: User = Depends(get_current_user),
):
with belief_scope("dataset_review.resume_clarification"):
session = _prepare_owned_session_mutation(
repository, session_id, current_user, session_version
)
@router.post('/sessions/{session_id}/clarification/resume', response_model=ClarificationStateResponse, dependencies=[Depends(_require_auto_review_flag), Depends(_require_clarification_flag), Depends(has_permission('dataset:session', 'MANAGE'))])
async def resume_clarification(session_id: str, session_version: int=Depends(_require_session_version_header), repository: DatasetReviewSessionRepository=Depends(_get_repository), clarification_engine: ClarificationEngine=Depends(_get_clarification_engine), current_user: User=Depends(get_current_user)):
with belief_scope('resume_clarification'):
logger.reason('Belief protocol reasoning checkpoint for resume_clarification')
session = _prepare_owned_session_mutation(repository, session_id, current_user, session_version)
clarification_session = _get_latest_clarification_session_or_404(session)
current_question = clarification_engine.build_question_payload(session)
return _serialize_clarification_state(
ClarificationStateResult(
clarification_session=clarification_session,
current_question=current_question,
session=session,
changed_findings=[],
)
)
logger.reflect('Belief protocol postcondition checkpoint for resume_clarification')
return _serialize_clarification_state(ClarificationStateResult(clarification_session=clarification_session, current_question=current_question, session=session, changed_findings=[]))
# [/DEF:resume_clarification:Function]

View File

@@ -4,9 +4,9 @@
# @SEMANTICS: git, routes, api, fastapi, repository, deployment
# @PURPOSE: Provides FastAPI endpoints for Git integration operations.
# @LAYER: API
# @RELATION: USES -> [backend.src.services.git_service.GitService]
# @RELATION: USES -> [GitService]
# @RELATION: USES -> [GitSchemas]
# @RELATION: USES -> [backend.src.models.git]
# @RELATION: USES -> [GitModels]
#
# @INVARIANT: All Git operations must be routed through GitService.
@@ -768,7 +768,7 @@ async def delete_gitea_repository(
# @POST: Repository is initialized on disk and a GitRepository record is saved in DB.
# @PARAM: dashboard_ref (str)
# @PARAM: init_data (RepoInitRequest)
# @RELATION: CALLS -> GitService.init_repo
# @RELATION: CALLS -> [GitService]
@router.post("/repositories/{dashboard_ref}/init")
async def init_repository(
dashboard_ref: str,
@@ -1090,7 +1090,7 @@ async def push_changes(
# @PRE: `dashboard_ref` repository exists and has a remote configured.
# @POST: Remote changes are fetched and merged into the local branch.
# @PARAM: dashboard_ref (str)
# @RELATION: CALLS -> GitService.pull
# @RELATION: CALLS -> [GitService]
@router.post("/repositories/{dashboard_ref}/pull")
async def pull_changes(
dashboard_ref: str,
@@ -1219,7 +1219,7 @@ async def get_merge_conflicts(
# @PURPOSE: Apply mine/theirs/manual conflict resolutions from WebUI and stage files.
# @PRE: `dashboard_ref` resolves; request contains at least one resolution item.
# @POST: Resolved files are staged in index.
# @RELATION: CALLS -> GitService.resolve_conflicts
# @RELATION: CALLS -> [GitService]
@router.post("/repositories/{dashboard_ref}/merge/resolve")
async def resolve_merge_conflicts(
dashboard_ref: str,
@@ -1279,7 +1279,7 @@ async def abort_merge(
# @PURPOSE: Finalize unfinished merge from WebUI flow.
# @PRE: All conflicts are resolved and staged.
# @POST: Merge commit is created.
# @RELATION: CALLS -> GitService.continue_merge
# @RELATION: CALLS -> [GitService]
@router.post("/repositories/{dashboard_ref}/merge/continue")
async def continue_merge(
dashboard_ref: str,
@@ -1310,7 +1310,7 @@ async def continue_merge(
# @POST: Dashboard YAMLs are exported from Superset and committed to Git.
# @PARAM: dashboard_ref (str)
# @PARAM: source_env_id (Optional[str])
# @RELATION: CALLS -> GitPlugin.execute
# @RELATION: CALLS -> [GitPlugin]
@router.post("/repositories/{dashboard_ref}/sync")
async def sync_dashboard(
dashboard_ref: str,
@@ -1348,7 +1348,7 @@ async def sync_dashboard(
# @PURPOSE: Promote changes between branches via MR or direct merge.
# @PRE: dashboard repository is initialized and Git config is valid.
# @POST: Returns promotion result metadata.
# @RELATION: CALLS -> GitPlugin.execute
# @RELATION: CALLS -> [GitPlugin]
@router.post("/repositories/{dashboard_ref}/promote", response_model=PromoteResponse)
async def promote_dashboard(
dashboard_ref: str,
@@ -1499,7 +1499,7 @@ async def get_environments(
# @POST: Dashboard YAMLs are read from Git and imported into the target Superset.
# @PARAM: dashboard_ref (str)
# @PARAM: deploy_data (DeployRequest)
# @RELATION: CALLS -> GitPlugin.execute
# @RELATION: CALLS -> [GitPlugin]
@router.post("/repositories/{dashboard_ref}/deploy")
async def deploy_dashboard(
dashboard_ref: str,
@@ -1677,7 +1677,7 @@ async def get_repository_diff(
# @PURPOSE: Generate a suggested commit message using LLM.
# @PRE: Repository for `dashboard_ref` is initialized.
# @POST: Returns a suggested commit message string.
# @RELATION: CALLS -> GitService.generate_commit_message
# @RELATION: CALLS -> [GitService]
@router.post("/repositories/{dashboard_ref}/generate-message")
async def generate_commit_message(
dashboard_ref: str,