feat(027): Final Phase T038-T043 implementation

- T038: SessionEvent logger and persistence logic
  - Added SessionEventLogger service with explicit audit event persistence
  - Added SessionEvent model with events relationship on DatasetReviewSession
  - Integrated event logging into orchestrator flows and API mutation endpoints

- T039: Semantic source version propagation
  - Added source_version column to SemanticFieldEntry
  - Added propagate_source_version_update() to SemanticResolver
  - Preserves locked/manual field invariants during propagation

- T040: Batch approval API and UI actions
  - Added batch semantic approval endpoint (/fields/semantic/approve-batch)
  - Added batch mapping approval endpoint (/mappings/approve-batch)
  - Added batch approval actions to SemanticLayerReview and ExecutionMappingReview components
  - Aligned batch semantics with single-item approval contracts

- T041: Superset compatibility matrix tests
  - Added test_superset_matrix.py with preview and SQL Lab fallback coverage
  - Tests verify client method preference and matrix fallback behavior

- T042: RBAC audit sweep on session-mutation endpoints
  - Added _require_owner_mutation_scope() helper
  - Applied owner guards to update_session, delete_session, and all mutation endpoints
  - Ensured no bypass of existing permission checks

- T043: i18n coverage for dataset-review UI
  - Added workspace state labels (empty/importing/review) to en.json and ru.json
  - Added batch action labels for semantics and mappings
  - Fixed workspace state comparison to lowercase strings
  - Removed hardcoded workspace state display strings

Signed-off-by: Implementation Specialist <impl@ss-tools>
This commit is contained in:
2026-03-17 14:29:33 +03:00
parent 38bda6a714
commit ed3d5f3039
33 changed files with 99234 additions and 93415 deletions

View File

@@ -664,6 +664,11 @@
"export_failed": "Failed to export the requested review artifact.",
"empty_state_title": "No session loaded",
"state_label": "Workspace",
"state": {
"empty": "Empty",
"importing": "Importing",
"review": "Review"
},
"readiness_label": "Readiness",
"source_badge_fallback": "review session",
"save_session_action": "Save session",
@@ -721,6 +726,8 @@
"preview_compiler_label": "Compiled by",
"preview_pending_note": "Compiled preview is not part of this US1 batch yet, but the workspace keeps the state visible when present.",
"jump_target_label": "Focused area",
"semantic_review_visible": "Semantic review is active for field-level source decisions.",
"clarification_visible": "Clarification is available with one active question at a time.",
"resume_action": "Resume session",
"pause_action": "Pause session",
"actions": {
@@ -765,6 +772,245 @@
"low_confidence": "Low confidence",
"unresolved": "Unresolved"
}
},
"semantics": {
"eyebrow": "Semantic layer",
"title": "Review semantic field values",
"description": "Compare the active semantic value with ranked candidates, preserve provenance, and lock or unlock manual decisions explicitly.",
"field_count_label": "Fields in review",
"empty": "No semantic fields need review right now.",
"unknown_source": "Unknown source",
"active_value_label": "Active semantic value",
"provenance_label": "Provenance",
"confidence_label": "Confidence",
"confidence_unset": "No confidence rank",
"confidence_rank_label": "Rank",
"source_label": "Source",
"changed_by_label": "Changed by",
"locked_badge": "Locked",
"unlocked_badge": "Unlocked",
"conflict_badge": "Conflict",
"needs_review_badge": "Needs review",
"manual_verbose_name_label": "Manual verbose name",
"manual_description_label": "Manual description",
"manual_display_format_label": "Manual display format",
"manual_override_action": "Manual override",
"approve_all_action": "Approve visible candidates",
"save_manual_action": "Save manual value",
"lock_action": "Lock field",
"unlock_action": "Unlock field",
"feedback_up_action": "👍",
"feedback_down_action": "👎",
"candidates_title": "Candidate options",
"candidates_empty": "No ranked candidate options were returned for this field.",
"candidate_description_empty": "No description proposed for this candidate.",
"display_format_label": "Display format",
"score_label": "Score",
"apply_candidate_action": "Apply",
"apply_and_lock_action": "Apply & lock",
"empty_value": "No current value",
"provenance": {
"unresolved": "Unresolved",
"dictionary_exact": "Dictionary exact match",
"reference_imported": "Imported reference",
"ai_generated": "AI generated",
"fuzzy_inferred": "Fuzzy inferred",
"manual_override": "Manual override"
},
"candidate_status": {
"pending": "Pending",
"accepted": "Accepted",
"superseded": "Superseded",
"rejected": "Rejected"
},
"messages": {
"saving": "Saving semantic decision...",
"save_failed": "Failed to save semantic decision.",
"manual_override_required": "Provide at least one manual semantic value before saving.",
"manual_saved": "Manual semantic value saved and locked.",
"candidate_applied": "Candidate value applied.",
"candidate_locked": "Candidate value applied and locked.",
"locked": "Field locked against silent overwrite.",
"unlocked": "Field unlocked for renewed review.",
"feedback_up": "Positive feedback recorded for this semantic value.",
"feedback_down": "Negative feedback recorded for this semantic value."
}
},
"clarification": {
"eyebrow": "Clarification",
"title": "Resolve one ambiguity at a time",
"description": "Answer the active clarification question, skip it, or send it to expert review while progress stays resumable.",
"progress_label": "Clarification progress",
"state_label": "Dialog state",
"status_label": "Status",
"remaining_label": "Remaining questions",
"summary_delta_label": "Summary delta",
"active_question_label": "Active question",
"why_it_matters_label": "Why it matters",
"current_guess_label": "Current guess",
"current_guess_empty": "No current guess is available.",
"topic_label": "Topic reference",
"options_title": "Available options",
"recommended_badge": "Recommended",
"custom_answer_label": "Custom answer",
"answer_action": "Answer with selected option",
"custom_answer_action": "Submit custom answer",
"skip_action": "Skip for now",
"assistant_action": "Open assistant guidance",
"expert_review_action": "Send to expert review",
"resume_action": "Resume clarification",
"completed": "No active clarification question remains. The session can be resumed later if new ambiguity appears.",
"messages": {
"saving": "Saving clarification answer...",
"saved": "Clarification answer saved.",
"skipped": "Question skipped and left resumable.",
"expert_review_requested": "Question escalated to expert review.",
"assistant_opened": "Assistant guidance opened for this clarification step.",
"resumed": "Clarification resumed from the highest-priority unresolved question.",
"resume_failed": "Failed to resume clarification.",
"save_failed": "Failed to save clarification answer.",
"option_required": "Select an option before submitting the answer.",
"custom_required": "Enter a custom answer before submitting."
}
},
"mapping": {
"eyebrow": "Template mapping",
"title": "Review filter-to-template mappings",
"description": "Verify imported filter values, effective execution values, and warning-sensitive transformations before preview or launch.",
"state_label": "Mapping state",
"state": {
"Incomplete": "Incomplete",
"WarningApproval": "Approval required",
"Approved": "Approved"
},
"pending_approvals_label": "Pending approvals",
"required_values_label": "Missing required values",
"empty": "No execution mappings are available yet.",
"required_blockers_notice": "{count} required values still need attention before preview or launch can proceed.",
"approval_notice": "{count} mapping transformations still need explicit approval.",
"to_variable_label": "To variable",
"required_badge": "Required",
"approval_required_badge": "Approval required",
"approved_badge": "Approved",
"source_filter_label": "Source filter",
"source_value_label": "Source value",
"confidence_label": "Confidence",
"recovery_label": "Recovery",
"effective_value_label": "Effective value",
"method_label": "Method",
"approval_label": "Approval",
"warning_label": "Warning",
"transformation_note_label": "Transformation note",
"missing_required_value": "This mapping still lacks a required effective value.",
"manual_value_label": "Manual effective value",
"manual_note_label": "Manual override note",
"save_override_action": "Save manual override",
"manual_override_action": "Manual override",
"approve_action": "Approve mapping",
"approve_all_action": "Approve all pending mappings",
"approval_state": {
"pending": "Pending",
"approved": "Approved",
"rejected": "Rejected",
"not_required": "Not required"
},
"warning_level": {
"none": "None",
"low": "Low",
"medium": "Medium",
"high": "High"
},
"method": {
"direct_match": "Direct match",
"heuristic_match": "Heuristic match",
"semantic_match": "Semantic match",
"manual_override": "Manual override"
},
"messages": {
"saving": "Saving mapping decision...",
"approval_saved": "Mapping approval recorded.",
"approval_failed": "Failed to save mapping approval.",
"override_saved": "Manual mapping override saved. Preview should be refreshed.",
"override_failed": "Failed to save manual mapping override.",
"required_value_missing": "Provide a required value before saving the manual override."
}
},
"preview": {
"eyebrow": "Compiled SQL preview",
"title": "Review Superset-compiled SQL",
"description": "Preview truth comes only from Superset. Regenerate the preview whenever mappings or required inputs change.",
"state_label": "Preview state",
"state": {
"missing": "Missing",
"pending": "Pending",
"ready": "Ready",
"stale": "Stale",
"failed": "Error"
},
"generate_action": "Generate SQL preview",
"generate_loading": "Generating preview...",
"missing_body": "No Superset preview is available yet. Generate one before attempting launch.",
"pending_body": "Superset is compiling the current execution context. Launch stays blocked until preview completes.",
"ready_body": "This SQL preview was compiled by Superset for the current execution inputs.",
"stale_body": "Mappings or effective values changed after the last successful preview. Regenerate before launch.",
"error_body": "Superset could not compile the current execution context.",
"compiler_label": "Compiled source",
"compiled_by_superset": "Compiled by Superset",
"compiled_source_unknown": "Compilation source unavailable",
"fingerprint_label": "Preview fingerprint",
"compiled_at_label": "Compiled at",
"sql_block_title": "Superset SQL",
"compiled_truth_note": "Exact SQL returned by Superset",
"go_to_mapping_action": "Review mapping inputs",
"review_inputs_action": "Review changed inputs",
"messages": {
"generated": "Superset preview refreshed.",
"generate_failed": "Failed to generate Superset preview."
}
},
"launch": {
"eyebrow": "Launch confirmation",
"title": "Confirm SQL Lab launch",
"description": "Launch remains blocked until preview truth, approvals, and readiness gates all match the reviewed execution context.",
"state_label": "Launch state",
"state": {
"Blocked": "Blocked",
"Ready": "Ready",
"Submitted": "Submitted"
},
"blocked_title": "Launch blockers",
"blocked_body": "Resolve the items below before sending this dataset run to SQL Lab.",
"resolve_action": "Open related area",
"dataset_ref_label": "Dataset reference",
"readiness_label": "Readiness",
"approved_mappings_label": "Approved mappings",
"preview_fingerprint_label": "Preview fingerprint",
"sql_lab_target_title": "Launch target",
"sql_lab_target_body": "The canonical launch target is a Superset SQL Lab session using the reviewed preview and effective execution inputs.",
"preview_status_label": "Preview status",
"compiled_by_label": "Compiled by",
"launch_action": "Launch dataset",
"launch_loading": "Launching dataset...",
"submitted_title": "Launch submitted",
"submitted_body": "SQL Lab handoff and audited run context were recorded for this launch request.",
"run_context_label": "Run context",
"sql_lab_session_label": "SQL Lab session",
"launch_status_label": "Launch status",
"preview_ref_label": "Preview reference",
"blockers": {
"blocking_finding": "Blocking findings remain unresolved",
"mapping_approval_required": "Mapping approval is still required",
"preview_missing": "Superset preview is required before launch",
"preview_pending": "Preview generation is still in progress",
"preview_stale": "Preview no longer matches the current execution inputs",
"preview_failed": "Preview failed and launch remains blocked",
"readiness_not_run_ready": "Session is not yet in run-ready state",
"preview_fingerprint_missing": "Preview fingerprint is missing, so launch cannot be trusted"
},
"messages": {
"launch_started": "Dataset launch request sent to SQL Lab.",
"launch_failed": "Failed to launch dataset in SQL Lab."
}
}
},
"tasks": {