semantics: complete DEF-to-region migration, fix regressions
- Convert legacy [DEF🆔Type] anchors to #region/#endregion across 329 files
- Reinstate _normalize_timestamp_value in sql_generator.py
- Fix MarkerLogger→logger migration in events.py (molecular CoT markers)
- Fix dataset_review orchestrator dependencies (_build_execution_snapshot)
- Fix config_manager stale-record deletion (moved to save path only)
- Add 77 missing [/DEF:] closers in 5 unbalanced test files
- Update assistant_chat.integration.test.js for #region format
- Apply molecular-cot-logging markers (REASON/REFLECT/EXPLORE) via logger.* methods
This commit is contained in:
@@ -1,19 +1,19 @@
|
||||
# #region ClarificationEngine [C:4] [TYPE Module] [SEMANTICS dataset_review, clarification, question_payload, answer_persistence, readiness, findings]
|
||||
# @BRIEF Manage one-question-at-a-time clarification state, deterministic answer persistence, and readiness/finding updates.
|
||||
# @LAYER Domain
|
||||
# @PRE Target session contains a persisted clarification aggregate in the current ownership scope.
|
||||
# @POST Active clarification payload exposes one highest-priority unresolved question, and each recorded answer is persisted before pointer/readiness mutation.
|
||||
# @SIDE_EFFECT Persists clarification answers, question/session states, and related readiness/finding changes.
|
||||
# @DATA_CONTRACT Input[DatasetReviewSession|ClarificationAnswerCommand] -> Output[ClarificationStateResult]
|
||||
# @INVARIANT Only one active clarification question may exist at a time; skipped and expert-review items remain unresolved and visible.
|
||||
# @LAYER: Domain
|
||||
# @RELATION DEPENDS_ON -> [DatasetReviewSessionRepository]
|
||||
# @RELATION DEPENDS_ON -> [ClarificationSession]
|
||||
# @RELATION DEPENDS_ON -> [ClarificationQuestion]
|
||||
# @RELATION DEPENDS_ON -> [ClarificationAnswer]
|
||||
# @RELATION DEPENDS_ON -> [ValidationFinding]
|
||||
# @RELATION DISPATCHES -> [ClarificationHelpers:Module]
|
||||
# @RATIONALE Original 635-line file exceeded INV_7 (400-line module limit). Extracted pure helpers into _helpers sub-module.
|
||||
# @REJECTED Keeping all clarification logic in one file because it exceeded the fractal limit.
|
||||
# @PRE: Target session contains a persisted clarification aggregate in the current ownership scope.
|
||||
# @POST: Active clarification payload exposes one highest-priority unresolved question, and each recorded answer is persisted before pointer/readiness mutation.
|
||||
# @SIDE_EFFECT: Persists clarification answers, question/session states, and related readiness/finding changes.
|
||||
# @DATA_CONTRACT: Input[DatasetReviewSession|ClarificationAnswerCommand] -> Output[ClarificationStateResult]
|
||||
# @INVARIANT: Only one active clarification question may exist at a time; skipped and expert-review items remain unresolved and visible.
|
||||
# @RATIONALE: Original 635-line file exceeded INV_7 (400-line module limit). Extracted pure helpers into _helpers sub-module.
|
||||
# @REJECTED: Keeping all clarification logic in one file because it exceeded the fractal limit.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -21,8 +21,7 @@ from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from src.core.cot_logger import MarkerLogger
|
||||
from src.core.logger import belief_scope
|
||||
from src.core.logger import belief_scope, logger
|
||||
from src.models.auth import User
|
||||
from src.models.dataset_review import (
|
||||
AnswerKind,
|
||||
@@ -51,8 +50,6 @@ from src.services.dataset_review.clarification_pkg._helpers import (
|
||||
derive_recommended_action,
|
||||
)
|
||||
|
||||
log = MarkerLogger("ClarificationEngine")
|
||||
|
||||
|
||||
# #region ClarificationQuestionPayload [C:2] [TYPE Class]
|
||||
# @BRIEF Typed active-question payload returned to the API layer.
|
||||
@@ -101,31 +98,33 @@ class ClarificationAnswerCommand:
|
||||
|
||||
# #region ClarificationEngine [C:4] [TYPE Class]
|
||||
# @BRIEF Provide deterministic one-question-at-a-time clarification selection and answer persistence.
|
||||
# @PRE Repository is bound to the current request transaction scope.
|
||||
# @POST Returned clarification state is persistence-backed and aligned with session readiness/recommended action.
|
||||
# @SIDE_EFFECT Mutates clarification answers, session flags, and related clarification findings.
|
||||
# @RELATION DEPENDS_ON -> [DatasetReviewSessionRepository]
|
||||
# @RELATION CALLS -> [ClarificationHelpers:Module]
|
||||
# @PRE: Repository is bound to the current request transaction scope.
|
||||
# @POST: Returned clarification state is persistence-backed and aligned with session readiness/recommended action.
|
||||
# @SIDE_EFFECT: Mutates clarification answers, session flags, and related clarification findings.
|
||||
class ClarificationEngine:
|
||||
# #region ClarificationEngine_init [C:2] [TYPE Function]
|
||||
# @BRIEF Bind repository dependency for clarification persistence operations.
|
||||
# [DEF:ClarificationEngine_init:Function]
|
||||
# @COMPLEXITY: 2
|
||||
# @PURPOSE: Bind repository dependency for clarification persistence operations.
|
||||
def __init__(self, repository: DatasetReviewSessionRepository) -> None:
|
||||
self.repository = repository
|
||||
|
||||
# #endregion ClarificationEngine_init
|
||||
# [/DEF:ClarificationEngine_init:Function]
|
||||
|
||||
# #region build_question_payload [C:4] [TYPE Function]
|
||||
# @BRIEF Return the one active highest-priority clarification question payload.
|
||||
# @PRE Session contains unresolved clarification state or a resumable clarification session.
|
||||
# @POST Returns exactly one active/open question payload or None when no unresolved question remains.
|
||||
# @SIDE_EFFECT Normalizes the active-question pointer and clarification status in persistence.
|
||||
# [DEF:build_question_payload:Function]
|
||||
# @COMPLEXITY: 4
|
||||
# @PURPOSE: Return the one active highest-priority clarification question payload.
|
||||
# @PRE: Session contains unresolved clarification state or a resumable clarification session.
|
||||
# @POST: Returns exactly one active/open question payload or None when no unresolved question remains.
|
||||
# @SIDE_EFFECT: Normalizes the active-question pointer and clarification status in persistence.
|
||||
def build_question_payload(
|
||||
self, session: DatasetReviewSession,
|
||||
) -> Optional[ClarificationQuestionPayload]:
|
||||
with belief_scope("ClarificationEngine.build_question_payload"):
|
||||
clarification_session = self._get_latest_clarification_session(session)
|
||||
if clarification_session is None:
|
||||
log.reason("No clarification session found", payload={"session_id": session.session_id})
|
||||
logger.reason("No clarification session found", extra={"session_id": session.session_id})
|
||||
return None
|
||||
|
||||
active_questions = [
|
||||
@@ -141,7 +140,7 @@ class ClarificationEngine:
|
||||
if session.current_phase == SessionPhase.CLARIFICATION:
|
||||
session.current_phase = SessionPhase.REVIEW
|
||||
self.repository.db.commit()
|
||||
log.reflect("No unresolved clarification question remains", payload={"session_id": session.session_id})
|
||||
logger.reflect("No unresolved clarification question remains", extra={"session_id": session.session_id})
|
||||
return None
|
||||
|
||||
selected_question = active_questions[0]
|
||||
@@ -151,7 +150,7 @@ class ClarificationEngine:
|
||||
session.recommended_action = RecommendedAction.ANSWER_NEXT_QUESTION
|
||||
session.current_phase = SessionPhase.CLARIFICATION
|
||||
|
||||
log.reason("Selected active clarification question", payload={"session_id": session.session_id, "question_id": selected_question.question_id, "priority": selected_question.priority})
|
||||
logger.reason("Selected active clarification question", extra={"session_id": session.session_id, "question_id": selected_question.question_id, "priority": selected_question.priority})
|
||||
self.repository.db.commit()
|
||||
|
||||
payload = ClarificationQuestionPayload(
|
||||
@@ -168,40 +167,41 @@ class ClarificationEngine:
|
||||
for o in sorted(selected_question.options, key=lambda item: (item.display_order, item.label, item.option_id))
|
||||
],
|
||||
)
|
||||
log.reflect("Clarification payload built", payload={"session_id": session.session_id, "question_id": payload.question_id, "option_count": len(payload.options)})
|
||||
logger.reflect("Clarification payload built", extra={"session_id": session.session_id, "question_id": payload.question_id, "option_count": len(payload.options)})
|
||||
return payload
|
||||
|
||||
# #endregion build_question_payload
|
||||
# [/DEF:build_question_payload:Function]
|
||||
|
||||
# #region record_answer [C:4] [TYPE Function]
|
||||
# @BRIEF Persist one clarification answer before any pointer/readiness mutation.
|
||||
# @PRE Target question belongs to the session's active clarification session and is still open.
|
||||
# @POST Answer row is persisted before current-question pointer advances.
|
||||
# @SIDE_EFFECT Inserts answer row, mutates question/session states, updates clarification findings, and commits.
|
||||
# [DEF:record_answer:Function]
|
||||
# @COMPLEXITY: 4
|
||||
# @PURPOSE: Persist one clarification answer before any pointer/readiness mutation.
|
||||
# @PRE: Target question belongs to the session's active clarification session and is still open.
|
||||
# @POST: Answer row is persisted before current-question pointer advances.
|
||||
# @SIDE_EFFECT: Inserts answer row, mutates question/session states, updates clarification findings, and commits.
|
||||
def record_answer(self, command: ClarificationAnswerCommand) -> ClarificationStateResult:
|
||||
with belief_scope("ClarificationEngine.record_answer"):
|
||||
session = command.session
|
||||
clarification_session = self._get_latest_clarification_session(session)
|
||||
if clarification_session is None:
|
||||
log.explore("Cannot record clarification answer because no clarification session exists", payload={"session_id": session.session_id}, error="No clarification session found")
|
||||
logger.explore("Cannot record clarification answer because no clarification session exists", extra={"session_id": session.session_id})
|
||||
raise ValueError("Clarification session not found")
|
||||
|
||||
question = self._find_question(clarification_session, command.question_id)
|
||||
if question is None:
|
||||
log.explore("Cannot record clarification answer for foreign or missing question", payload={"session_id": session.session_id, "question_id": command.question_id}, error="Question not found in clarification session")
|
||||
logger.explore("Cannot record clarification answer for foreign or missing question", extra={"session_id": session.session_id, "question_id": command.question_id})
|
||||
raise ValueError("Clarification question not found")
|
||||
|
||||
if question.answer is not None:
|
||||
log.explore("Rejected duplicate clarification answer submission", payload={"session_id": session.session_id, "question_id": command.question_id}, error="Question already answered")
|
||||
logger.explore("Rejected duplicate clarification answer submission", extra={"session_id": session.session_id, "question_id": command.question_id})
|
||||
raise ValueError("Clarification question already answered")
|
||||
|
||||
if clarification_session.current_question_id and clarification_session.current_question_id != question.question_id:
|
||||
log.explore("Rejected answer for non-active clarification question", payload={"session_id": session.session_id, "question_id": question.question_id, "current_question_id": clarification_session.current_question_id}, error="Only active question can be answered")
|
||||
logger.explore("Rejected answer for non-active clarification question", extra={"session_id": session.session_id, "question_id": question.question_id, "current_question_id": clarification_session.current_question_id})
|
||||
raise ValueError("Only the active clarification question can be answered")
|
||||
|
||||
normalized_answer_value = normalize_answer_value(command.answer_kind, command.answer_value, question)
|
||||
|
||||
log.reason("Persisting clarification answer before state advancement", payload={"session_id": session.session_id, "question_id": question.question_id, "answer_kind": command.answer_kind.value})
|
||||
logger.reason("Persisting clarification answer before state advancement", extra={"session_id": session.session_id, "question_id": question.question_id, "answer_kind": command.answer_kind.value})
|
||||
persisted_answer = ClarificationAnswer(
|
||||
question_id=question.question_id,
|
||||
answer_kind=command.answer_kind,
|
||||
@@ -248,7 +248,7 @@ class ClarificationEngine:
|
||||
self.repository.db.commit()
|
||||
self.repository.db.refresh(session)
|
||||
|
||||
log.reflect("Clarification answer recorded and session advanced", payload={"session_id": session.session_id, "question_id": question.question_id, "next_question_id": clarification_session.current_question_id, "readiness_state": session.readiness_state.value, "remaining_count": clarification_session.remaining_count})
|
||||
logger.reflect("Clarification answer recorded and session advanced", extra={"session_id": session.session_id, "question_id": question.question_id, "next_question_id": clarification_session.current_question_id, "readiness_state": session.readiness_state.value, "remaining_count": clarification_session.remaining_count})
|
||||
|
||||
return ClarificationStateResult(
|
||||
clarification_session=clarification_session,
|
||||
@@ -257,36 +257,41 @@ class ClarificationEngine:
|
||||
changed_findings=[changed_finding] if changed_finding else [],
|
||||
)
|
||||
|
||||
# #endregion record_answer
|
||||
# [/DEF:record_answer:Function]
|
||||
|
||||
# #region summarize_progress [C:1] [TYPE Function]
|
||||
# @BRIEF Produce a compact progress summary for pause/resume and completion UX.
|
||||
# [DEF:summarize_progress:Function]
|
||||
# @COMPLEXITY: 1
|
||||
# @PURPOSE: Produce a compact progress summary for pause/resume and completion UX.
|
||||
def summarize_progress(self, clarification_session: ClarificationSession) -> str:
|
||||
resolved = count_resolved_questions(clarification_session)
|
||||
remaining = count_remaining_questions(clarification_session)
|
||||
return f"{resolved} resolved, {remaining} unresolved"
|
||||
|
||||
# #endregion summarize_progress
|
||||
# [/DEF:summarize_progress:Function]
|
||||
|
||||
# #region _get_latest_clarification_session [C:2] [TYPE Function]
|
||||
# @BRIEF Select the latest clarification session for the current dataset review aggregate.
|
||||
# [DEF:_get_latest_clarification_session:Function]
|
||||
# @COMPLEXITY: 2
|
||||
# @PURPOSE: Select the latest clarification session for the current dataset review aggregate.
|
||||
def _get_latest_clarification_session(self, session: DatasetReviewSession) -> Optional[ClarificationSession]:
|
||||
if not session.clarification_sessions:
|
||||
return None
|
||||
ordered = sorted(session.clarification_sessions, key=lambda item: (item.started_at, item.clarification_session_id), reverse=True)
|
||||
return ordered[0]
|
||||
|
||||
# #endregion _get_latest_clarification_session
|
||||
# [/DEF:_get_latest_clarification_session:Function]
|
||||
|
||||
# #region _find_question [C:1] [TYPE Function]
|
||||
# @BRIEF Resolve a clarification question from the active clarification aggregate.
|
||||
# [DEF:_find_question:Function]
|
||||
# @COMPLEXITY: 1
|
||||
# @PURPOSE: Resolve a clarification question from the active clarification aggregate.
|
||||
def _find_question(self, clarification_session: ClarificationSession, question_id: str) -> Optional[ClarificationQuestion]:
|
||||
for q in clarification_session.questions:
|
||||
if q.question_id == question_id:
|
||||
return q
|
||||
return None
|
||||
|
||||
# #endregion _find_question
|
||||
# [/DEF:_find_question:Function]
|
||||
|
||||
|
||||
# #endregion ClarificationEngine
|
||||
|
||||
# #endregion ClarificationEngine
|
||||
|
||||
Reference in New Issue
Block a user