skills + agents

This commit is contained in:
2026-04-19 20:05:45 +03:00
parent 2228a00035
commit 277ce7b3b3
40 changed files with 1155 additions and 1868 deletions

View File

@@ -1477,6 +1477,44 @@ def test_mutation_endpoints_surface_session_version_conflict_payload(
# [/DEF:test_mutation_endpoints_surface_session_version_conflict_payload:Function]
# [DEF:test_update_session_surfaces_commit_time_session_version_conflict_payload:Function]
# @RELATION: BINDS_TO -> DatasetReviewApiTests
# @PURPOSE: Session lifecycle mutation should return deterministic 409 conflict semantics when commit-time optimistic locking rejects a stale write.
def test_update_session_surfaces_commit_time_session_version_conflict_payload(
dataset_review_api_dependencies,
):
session = _make_session()
repository = MagicMock()
repository.load_session_detail.return_value = session
repository.require_session_version.return_value = session
repository.commit_session_mutation.side_effect = (
DatasetReviewSessionVersionConflictError(
session_id="sess-1",
expected_version=0,
actual_version=1,
)
)
repository.db = MagicMock()
repository.event_logger = MagicMock(spec=SessionEventLogger)
app.dependency_overrides[_get_repository] = lambda: repository
response = client.patch(
"/api/dataset-orchestration/sessions/sess-1",
json={"status": "paused"},
headers={"X-Session-Version": "0"},
)
assert response.status_code == 409
payload = response.json()["detail"]
assert payload["error_code"] == "session_version_conflict"
assert payload["expected_version"] == 0
assert payload["actual_version"] == 1
# [/DEF:test_update_session_surfaces_commit_time_session_version_conflict_payload:Function]
# [DEF:test_execution_snapshot_includes_recovered_imported_filters_without_template_mapping:Function]
# @RELATION: BINDS_TO -> DatasetReviewApiTests
# @PURPOSE: Recovered imported filters with values should flow into preview filter context even when no template variable mapping exists.

View File

@@ -69,8 +69,8 @@ class RevokeRequest(dict):
# @PRE: Payload contains required fields (id, version, source_snapshot_ref, created_by).
# @POST: Candidate is saved in repository.
# @RETURN: CandidateDTO
# @RELATION: CALLS -> [CleanReleaseRepository.save_candidate]
# @RELATION: DEPENDS_ON -> [CandidateDTO]
# @RELATION: DEPENDS_ON -> [CleanReleaseRepository]
# @RELATION: DEPENDS_ON -> [clean_release_dto]
@router.post(
"/candidates", response_model=CandidateDTO, status_code=status.HTTP_201_CREATED
)
@@ -105,7 +105,7 @@ async def register_candidate(
# @PURPOSE: Associate artifacts with a release candidate.
# @PRE: Candidate exists.
# @POST: Artifacts are processed (placeholder).
# @RELATION: CALLS -> [CleanReleaseRepository.get_candidate]
# @RELATION: DEPENDS_ON -> [CleanReleaseRepository]
@router.post("/candidates/{candidate_id}/artifacts")
async def import_artifacts(
candidate_id: str,
@@ -140,8 +140,7 @@ async def import_artifacts(
# @PRE: Candidate exists.
# @POST: Manifest is created and saved.
# @RETURN: ManifestDTO
# @RELATION: CALLS -> [CleanReleaseRepository.save_manifest]
# @RELATION: CALLS -> [CleanReleaseRepository.get_candidate]
# @RELATION: DEPENDS_ON -> [CleanReleaseRepository]
@router.post(
"/candidates/{candidate_id}/manifests",
response_model=ManifestDTO,

View File

@@ -480,16 +480,7 @@ def _enforce_session_version(
"actual_version": exc.actual_version,
},
)
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail={
"error_code": "session_version_conflict",
"message": str(exc),
"session_id": exc.session_id,
"expected_version": exc.expected_version,
"actual_version": exc.actual_version,
},
) from exc
raise _build_session_version_conflict_http_exception(exc) from exc
logger.reflect(
"Dataset review optimistic-lock version accepted",
extra={
@@ -498,9 +489,33 @@ def _enforce_session_version(
},
)
return session
# [/DEF:_enforce_session_version:Function]
# [DEF:_build_session_version_conflict_http_exception:Function]
# @COMPLEXITY: 2
# @PURPOSE: Normalize optimistic-lock conflict errors into deterministic dataset-review HTTP 409 responses.
# @RELATION: [DEPENDS_ON] ->[DatasetReviewSessionVersionConflictError]
def _build_session_version_conflict_http_exception(
exc: DatasetReviewSessionVersionConflictError,
) -> HTTPException:
return HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail={
"error_code": "session_version_conflict",
"message": str(exc),
"session_id": exc.session_id,
"expected_version": exc.expected_version,
"actual_version": exc.actual_version,
},
)
# [/DEF:_build_session_version_conflict_http_exception:Function]
# [DEF:_prepare_owned_session_mutation:Function]
# @COMPLEXITY: 4
# @PURPOSE: Resolve owner-scoped mutation session and enforce optimistic-lock version before changing dataset review state.
@@ -524,7 +539,9 @@ def _prepare_owned_session_mutation(
)
session = _get_owned_session_or_404(repository, session_id, current_user)
_require_owner_mutation_scope(session, current_user)
guarded_session = _enforce_session_version(repository, session, expected_version)
guarded_session = _enforce_session_version(
repository, session, expected_version
)
logger.reflect(
"Dataset review mutation session passed ownership and version guards",
extra={
@@ -534,6 +551,8 @@ def _prepare_owned_session_mutation(
},
)
return guarded_session
# [/DEF:_prepare_owned_session_mutation:Function]
@@ -556,11 +575,21 @@ def _commit_owned_session_mutation(
"Committing dataset review mutation",
extra={"session_id": session.session_id},
)
repository.bump_session_version(session)
repository.db.commit()
repository.db.refresh(session)
for target in refresh_targets or []:
repository.db.refresh(target)
try:
repository.commit_session_mutation(
session,
refresh_targets=refresh_targets,
)
except DatasetReviewSessionVersionConflictError as exc:
logger.explore(
"Dataset review mutation commit detected stale version",
extra={
"session_id": exc.session_id,
"expected_version": exc.expected_version,
"actual_version": exc.actual_version,
},
)
raise _build_session_version_conflict_http_exception(exc) from exc
logger.reflect(
"Dataset review mutation committed and refreshed",
extra={
@@ -570,6 +599,8 @@ def _commit_owned_session_mutation(
},
)
return session
# [/DEF:_commit_owned_session_mutation:Function]
@@ -678,7 +709,7 @@ def _get_owned_session_or_404(
"Resolving dataset review session in current ownership scope",
extra={"session_id": session_id, "user_id": current_user.id},
)
session = repository.load_detail(session_id, current_user.id)
session = repository.load_session_detail(session_id, current_user.id)
if session is None:
logger.explore(
"Dataset review session not found in current ownership scope",
@@ -1224,9 +1255,21 @@ async def list_sessions(
# @POST: returns persisted session summary scoped to the authenticated user.
# @SIDE_EFFECT: persists session/profile/findings and may enqueue recovery task.
# @DATA_CONTRACT: Input[StartSessionRequest] -> Output[SessionSummary]
@router.post('/sessions', response_model=SessionSummary, status_code=status.HTTP_201_CREATED, dependencies=[Depends(_require_auto_review_flag), Depends(has_permission('dataset:session', 'MANAGE'))])
async def start_session(request: StartSessionRequest, orchestrator: DatasetReviewOrchestrator=Depends(_get_orchestrator), current_user: User=Depends(get_current_user)):
with belief_scope('start_session'):
@router.post(
"/sessions",
response_model=SessionSummary,
status_code=status.HTTP_201_CREATED,
dependencies=[
Depends(_require_auto_review_flag),
Depends(has_permission("dataset:session", "MANAGE")),
],
)
async def start_session(
request: StartSessionRequest,
orchestrator: DatasetReviewOrchestrator = Depends(_get_orchestrator),
current_user: User = Depends(get_current_user),
):
with belief_scope("start_session"):
logger.reason(
"Starting dataset review session",
extra={
@@ -1236,11 +1279,25 @@ async def start_session(request: StartSessionRequest, orchestrator: DatasetRevie
},
)
try:
result = orchestrator.start_session(StartSessionCommand(user=current_user, environment_id=request.environment_id, source_kind=request.source_kind, source_input=request.source_input))
result = orchestrator.start_session(
StartSessionCommand(
user=current_user,
environment_id=request.environment_id,
source_kind=request.source_kind,
source_input=request.source_input,
)
)
except ValueError as exc:
logger.explore('Dataset review session start rejected', extra={'user_id': current_user.id, 'error': str(exc)})
logger.explore(
"Dataset review session start rejected",
extra={"user_id": current_user.id, "error": str(exc)},
)
detail = str(exc)
status_code = status.HTTP_404_NOT_FOUND if detail == 'Environment not found' else status.HTTP_400_BAD_REQUEST
status_code = (
status.HTTP_404_NOT_FOUND
if detail == "Environment not found"
else status.HTTP_400_BAD_REQUEST
)
raise HTTPException(status_code=status_code, detail=detail) from exc
logger.reflect(
"Dataset review session started and serialized",
@@ -1250,6 +1307,8 @@ async def start_session(request: StartSessionRequest, orchestrator: DatasetRevie
},
)
return _serialize_session_summary(result.session)
# [/DEF:start_session:Function]
@@ -1295,9 +1354,22 @@ async def get_session_detail(
# @POST: returns updated summary without changing ownership or unrelated aggregates.
# @SIDE_EFFECT: mutates session lifecycle fields in persistence.
# @DATA_CONTRACT: Input[UpdateSessionRequest] -> Output[SessionSummary]
@router.patch('/sessions/{session_id}', response_model=SessionSummary, dependencies=[Depends(_require_auto_review_flag), Depends(has_permission('dataset:session', 'MANAGE'))])
async def update_session(session_id: str, request: UpdateSessionRequest, session_version: int=Depends(_require_session_version_header), repository: DatasetReviewSessionRepository=Depends(_get_repository), current_user: User=Depends(get_current_user)):
with belief_scope('update_session'):
@router.patch(
"/sessions/{session_id}",
response_model=SessionSummary,
dependencies=[
Depends(_require_auto_review_flag),
Depends(has_permission("dataset:session", "MANAGE")),
],
)
async def update_session(
session_id: str,
request: UpdateSessionRequest,
session_version: int = Depends(_require_session_version_header),
repository: DatasetReviewSessionRepository = Depends(_get_repository),
current_user: User = Depends(get_current_user),
):
with belief_scope("update_session"):
logger.reason(
"Updating dataset review session lifecycle state",
extra={
@@ -1306,17 +1378,31 @@ async def update_session(session_id: str, request: UpdateSessionRequest, session
"requested_status": request.status.value,
},
)
session = _prepare_owned_session_mutation(repository, session_id, current_user, session_version)
session = _prepare_owned_session_mutation(
repository, session_id, current_user, session_version
)
session_record = cast(Any, session)
session_record.status = request.status
if request.status == SessionStatus.PAUSED:
session_record.recommended_action = RecommendedAction.RESUME_SESSION
elif request.status in {SessionStatus.ARCHIVED, SessionStatus.CANCELLED, SessionStatus.COMPLETED}:
elif request.status in {
SessionStatus.ARCHIVED,
SessionStatus.CANCELLED,
SessionStatus.COMPLETED,
}:
session_record.active_task_id = None
repository.bump_session_version(session)
repository.db.commit()
repository.db.refresh(session)
_record_session_event(repository, session, current_user, event_type='session_status_updated', event_summary='Dataset review session lifecycle updated', event_details={'status': session_record.status.value, 'version': session_record.version})
_commit_owned_session_mutation(repository, session)
_record_session_event(
repository,
session,
current_user,
event_type="session_status_updated",
event_summary="Dataset review session lifecycle updated",
event_details={
"status": session_record.status.value,
"version": session_record.version,
},
)
logger.reflect(
"Dataset review session lifecycle updated",
extra={
@@ -1327,11 +1413,11 @@ async def update_session(session_id: str, request: UpdateSessionRequest, session
},
)
return _serialize_session_summary(session)
# [/DEF:update_session:Function]
from src.logger import belief_scope, logger
# [DEF:delete_session:Function]
# @COMPLEXITY: 4
# @PURPOSE: Archive or hard-delete a session owned by the current user.
@@ -1340,9 +1426,22 @@ from src.logger import belief_scope, logger
# @POST: session is archived or deleted and no foreign-session existence is disclosed.
# @SIDE_EFFECT: mutates or deletes persisted session aggregate.
# @DATA_CONTRACT: Input[session_id:str,hard_delete:bool] -> Output[HTTP 204]
@router.delete('/sessions/{session_id}', status_code=status.HTTP_204_NO_CONTENT, dependencies=[Depends(_require_auto_review_flag), Depends(has_permission('dataset:session', 'MANAGE'))])
async def delete_session(session_id: str, hard_delete: bool=Query(False), session_version: int=Depends(_require_session_version_header), repository: DatasetReviewSessionRepository=Depends(_get_repository), current_user: User=Depends(get_current_user)):
with belief_scope('delete_session'):
@router.delete(
"/sessions/{session_id}",
status_code=status.HTTP_204_NO_CONTENT,
dependencies=[
Depends(_require_auto_review_flag),
Depends(has_permission("dataset:session", "MANAGE")),
],
)
async def delete_session(
session_id: str,
hard_delete: bool = Query(False),
session_version: int = Depends(_require_session_version_header),
repository: DatasetReviewSessionRepository = Depends(_get_repository),
current_user: User = Depends(get_current_user),
):
with belief_scope("delete_session"):
logger.reason(
"Deleting or archiving dataset review session",
extra={
@@ -1351,9 +1450,18 @@ async def delete_session(session_id: str, hard_delete: bool=Query(False), sessio
"hard_delete": hard_delete,
},
)
session = _prepare_owned_session_mutation(repository, session_id, current_user, session_version)
session = _prepare_owned_session_mutation(
repository, session_id, current_user, session_version
)
if hard_delete:
_record_session_event(repository, session, current_user, event_type='session_deleted', event_summary='Dataset review session hard-deleted', event_details={'hard_delete': True})
_record_session_event(
repository,
session,
current_user,
event_type="session_deleted",
event_summary="Dataset review session hard-deleted",
event_details={"hard_delete": True},
)
repository.db.delete(session)
repository.db.commit()
logger.reflect(
@@ -1365,7 +1473,14 @@ async def delete_session(session_id: str, hard_delete: bool=Query(False), sessio
session_record.status = SessionStatus.ARCHIVED
session_record.active_task_id = None
_commit_owned_session_mutation(repository, session)
_record_session_event(repository, session, current_user, event_type='session_archived', event_summary='Dataset review session archived', event_details={'hard_delete': False, 'version': session_record.version})
_record_session_event(
repository,
session,
current_user,
event_type="session_archived",
event_summary="Dataset review session archived",
event_details={"hard_delete": False, "version": session_record.version},
)
logger.reflect(
"Dataset review session archive committed",
extra={
@@ -1375,6 +1490,8 @@ async def delete_session(session_id: str, hard_delete: bool=Query(False), sessio
},
)
return Response(status_code=status.HTTP_204_NO_CONTENT)
# [/DEF:delete_session:Function]
@@ -1386,11 +1503,26 @@ async def delete_session(session_id: str, hard_delete: bool=Query(False), sessio
# @POST: returns ownership-scoped export payload without fabricating unrelated artifacts.
# @SIDE_EFFECT: none beyond response construction.
# @DATA_CONTRACT: Input[session_id:str,format:ArtifactFormat] -> Output[ExportArtifactResponse]
@router.get('/sessions/{session_id}/exports/documentation', response_model=ExportArtifactResponse, dependencies=[Depends(_require_auto_review_flag), Depends(has_permission('dataset:session', 'READ'))])
async def export_documentation(session_id: str, format: ArtifactFormat=Query(ArtifactFormat.JSON), repository: DatasetReviewSessionRepository=Depends(_get_repository), current_user: User=Depends(get_current_user)):
with belief_scope('export_documentation'):
@router.get(
"/sessions/{session_id}/exports/documentation",
response_model=ExportArtifactResponse,
dependencies=[
Depends(_require_auto_review_flag),
Depends(has_permission("dataset:session", "READ")),
],
)
async def export_documentation(
session_id: str,
format: ArtifactFormat = Query(ArtifactFormat.JSON),
repository: DatasetReviewSessionRepository = Depends(_get_repository),
current_user: User = Depends(get_current_user),
):
with belief_scope("export_documentation"):
if format not in {ArtifactFormat.JSON, ArtifactFormat.MARKDOWN}:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Only json and markdown exports are supported')
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Only json and markdown exports are supported",
)
logger.reason(
"Building dataset review documentation export",
extra={
@@ -1409,7 +1541,17 @@ async def export_documentation(session_id: str, format: ArtifactFormat=Query(Art
"format": format.value,
},
)
return ExportArtifactResponse(artifact_id=f'documentation-{session.session_id}-{format.value}', session_id=session.session_id, artifact_type='documentation', format=format.value, storage_ref=export_payload['storage_ref'], created_by_user_id=current_user.id, content=export_payload['content'])
return ExportArtifactResponse(
artifact_id=f"documentation-{session.session_id}-{format.value}",
session_id=session.session_id,
artifact_type="documentation",
format=format.value,
storage_ref=export_payload["storage_ref"],
created_by_user_id=current_user.id,
content=export_payload["content"],
)
# [/DEF:export_documentation:Function]
@@ -1421,11 +1563,26 @@ async def export_documentation(session_id: str, format: ArtifactFormat=Query(Art
# @POST: returns explicit validation export payload scoped to current user session access.
# @SIDE_EFFECT: none beyond response construction.
# @DATA_CONTRACT: Input[session_id:str,format:ArtifactFormat] -> Output[ExportArtifactResponse]
@router.get('/sessions/{session_id}/exports/validation', response_model=ExportArtifactResponse, dependencies=[Depends(_require_auto_review_flag), Depends(has_permission('dataset:session', 'READ'))])
async def export_validation(session_id: str, format: ArtifactFormat=Query(ArtifactFormat.JSON), repository: DatasetReviewSessionRepository=Depends(_get_repository), current_user: User=Depends(get_current_user)):
with belief_scope('export_validation'):
@router.get(
"/sessions/{session_id}/exports/validation",
response_model=ExportArtifactResponse,
dependencies=[
Depends(_require_auto_review_flag),
Depends(has_permission("dataset:session", "READ")),
],
)
async def export_validation(
session_id: str,
format: ArtifactFormat = Query(ArtifactFormat.JSON),
repository: DatasetReviewSessionRepository = Depends(_get_repository),
current_user: User = Depends(get_current_user),
):
with belief_scope("export_validation"):
if format not in {ArtifactFormat.JSON, ArtifactFormat.MARKDOWN}:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Only json and markdown exports are supported')
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Only json and markdown exports are supported",
)
logger.reason(
"Building dataset review validation export",
extra={
@@ -1444,7 +1601,17 @@ async def export_validation(session_id: str, format: ArtifactFormat=Query(Artifa
"format": format.value,
},
)
return ExportArtifactResponse(artifact_id=f'validation-{session.session_id}-{format.value}', session_id=session.session_id, artifact_type='validation_report', format=format.value, storage_ref=export_payload['storage_ref'], created_by_user_id=current_user.id, content=export_payload['content'])
return ExportArtifactResponse(
artifact_id=f"validation-{session.session_id}-{format.value}",
session_id=session.session_id,
artifact_type="validation_report",
format=format.value,
storage_ref=export_payload["storage_ref"],
created_by_user_id=current_user.id,
content=export_payload["content"],
)
# [/DEF:export_validation:Function]
@@ -1456,18 +1623,46 @@ 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('get_clarification_state'):
logger.reason('Belief protocol reasoning checkpoint for 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')
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)
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=[]))
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]
@@ -1479,15 +1674,42 @@ async def get_clarification_state(session_id: str, repository: DatasetReviewSess
# @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('resume_clarification'):
logger.reason('Belief protocol reasoning checkpoint for 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)
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=[]))
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]
@@ -2040,6 +2262,8 @@ async def trigger_preview_generation(
expected_version=session_version,
)
)
except DatasetReviewSessionVersionConflictError as exc:
raise _build_session_version_conflict_http_exception(exc) from exc
except ValueError as exc:
detail = str(exc)
status_code = (
@@ -2108,6 +2332,8 @@ async def launch_dataset(
expected_version=session_version,
)
)
except DatasetReviewSessionVersionConflictError as exc:
raise _build_session_version_conflict_http_exception(exc) from exc
except ValueError as exc:
detail = str(exc)
status_code = (