Files
ss-tools/backend/src/plugins/translate/dictionary_correction.py
busya 8e8a3c3235 feat: attention-optimized semantic protocol v2.7
Core changes:
- Add @defgroup/@ingroup to 1791 C2+ contracts (555 files) for HCA 128× pre-training DSA grouping
- Add §0.1 Pre-Training Frequency matrix to semantics-core
- Add §VIII Attention Architecture rules (ATTN_1-4) with MLA/CSA/HCA/DSA mechanics
- Add @defgroup/@ingroup to canonical syntax (§II) and all contract examples

Agent prompts (5 files):
- Add ZERO-STATE RATIONALE with MLA/CSA/HCA/DSA compression mechanics
- Add pre-training note: @RATIONALE/@REJECTED are in-context learned tags
- svelte-coder: add missing #region contract, fix Svelte rule violations
- python-coder/fullstack-coder: honor function contracts from speckit plan
- qa-tester: add attention compliance audit (P3 ATTN_1-4 checks)

Skills (6 files):
- Translate all axiom_config descriptions to English
- Fix doc_dirs to index .opencode/ and .specify/
- Deduplicate 5× complexity_rules → single global_tags catalog
- Reduce semantics-svelte 591→485 lines (remove duplicate code blocks)
- Fix semantics-testing: 'Short IDs' → 'Short hierarchical IDs'
- Fix all examples: flat IDs → hierarchical Domain.Name format
- Fix Svelte examples: replace raw Tailwind + <button> with semantic tokens + /ui

Speckit workflow (commands + templates):
- speckit.plan: add Function-Level Contracts for C3+ with @PRE/@POST/@TEST_EDGE
- speckit.plan: add Attention Compliance Gate (ATTN_1-4 before contract generation)
- speckit.tasks: add function contract inlining format (constraints in task description)
- speckit.specify: load semantics-core for spec density rules
- spec-template: add #region contract, @SEMANTICS grouping, hierarchical IDs
- ux-reference-template: add #region wrapper
- plan-template: add attention gate, @defgroup/@ingroup guidance
- tasks-template: add attention audit + rebuild + orphan check tasks
- constitution.md: translate to English, add Principle VIII (attention-optimized contracts)

Reference modules rewritten (hierarchical IDs + full contracts):
- Auth.Jwt: 6 child contracts with @RATIONALE/@REJECTED/@TEST_EDGE
- Api.Auth: 5 endpoints with @TEST_EDGE + molecular CoT markers
- Migration.Model: @defgroup Migration with 18 @ACTION + 6 @INVARIANT

Scripts:
- add_defgroup_ingroup.py: zero-risk additive @ingroup migration (1791 insertions)
- migrate_hierarchical.py: flat→hierarchical ID dry-run analysis (792 contracts)
- merge_prompts.py: merge all prompts/skills/commands into one review file

Config:
- axiom_config.yaml: 749→395 lines (-47%), English, doc_dirs include prompts
- Fix test_datasets.py import collision (rename → test_datasets_routes.py)
- Fix test_preview.py: SupersetClient→get_superset_client, AsyncMock, logger f-string
2026-06-08 16:30:59 +03:00

194 lines
9.8 KiB
Python

# #region DictionaryCorrectionService [C:3] [TYPE Class] [SEMANTICS dictionary, correction, bulk]
# @defgroup Translate Module group.
# @BRIEF Submit term corrections and bulk corrections to dictionaries with conflict detection.
# @RELATION DEPENDS_ON -> [DictionaryEntry]
# @RELATION DEPENDS_ON -> [TerminologyDictionary]
from typing import Any
from sqlalchemy import or_
from sqlalchemy.orm import Session
from ...core.logger import belief_scope, logger
from ...models.translate import DictionaryEntry, TerminologyDictionary
from ._utils import _normalize_term
class DictionaryCorrectionService:
"""Submit term corrections to dictionaries with conflict detection and bulk support."""
# region submit_correction [TYPE Function]
# @PURPOSE: Submit a term correction from a run result.
@staticmethod
def submit_correction(
db: Session,
dict_id: str,
source_term: str,
incorrect_target_term: str,
corrected_target_term: str,
origin_run_id: str | None = None,
origin_row_key: str | None = None,
origin_user_id: str | None = None,
on_conflict: str = "overwrite",
context_data: dict[str, Any] | None = None,
usage_notes: str | None = None,
keep_context: bool = True,
) -> dict[str, Any]:
with belief_scope("DictionaryCorrectionService.submit_correction"):
dictionary = db.query(TerminologyDictionary).filter(TerminologyDictionary.id == dict_id).first()
if not dictionary:
raise ValueError(f"Dictionary '{dict_id}' not found")
effective_context = context_data
effective_context_source = "auto"
if not keep_context:
effective_context = None
effective_context_source = "manual"
normalized = _normalize_term(source_term)
entry_src_lang = "und"
entry_tgt_lang = "und"
existing = (
db.query(DictionaryEntry)
.filter(
DictionaryEntry.dictionary_id == dict_id,
DictionaryEntry.source_term_normalized == normalized,
or_(
(DictionaryEntry.source_language == entry_src_lang) & (DictionaryEntry.target_language == entry_tgt_lang),
(DictionaryEntry.source_language == "und") & (DictionaryEntry.target_language == "und"),
),
)
.first()
)
result: dict[str, Any] = {"source_term": source_term, "target_term": corrected_target_term, "action": "created", "entry_id": None, "conflict": None, "message": None}
if existing:
if on_conflict == "keep_existing":
result["action"] = "conflict_detected"
result["conflict"] = {"source_term": source_term, "existing_target_term": existing.target_term, "submitted_target_term": corrected_target_term, "action": "keep_existing"}
result["message"] = f"Existing entry kept: '{existing.target_term}'"
return result
elif on_conflict == "overwrite":
existing.target_term = corrected_target_term.strip()
if origin_run_id:
existing.origin_run_id = origin_run_id
if origin_row_key:
existing.origin_row_key = origin_row_key
if origin_user_id:
existing.origin_user_id = origin_user_id
if context_data is not None or not keep_context:
existing.context_data = effective_context
existing.has_context = bool(effective_context)
existing.context_source = effective_context_source
if usage_notes is not None:
existing.usage_notes = usage_notes
db.flush()
result["action"] = "updated"
result["entry_id"] = existing.id
result["message"] = f"Entry updated from '{existing.target_term}' to '{corrected_target_term}'"
else:
result["action"] = "skipped"
result["conflict"] = {"source_term": source_term, "existing_target_term": existing.target_term, "submitted_target_term": corrected_target_term, "action": "cancel"}
result["message"] = "Correction cancelled by conflict mode"
return result
else:
entry = DictionaryEntry(
dictionary_id=dict_id, source_term=source_term.strip(),
source_term_normalized=normalized, target_term=corrected_target_term.strip(),
source_language=entry_src_lang, target_language=entry_tgt_lang,
context_data=effective_context, usage_notes=usage_notes,
has_context=bool(effective_context), context_source=effective_context_source if effective_context else None,
origin_run_id=origin_run_id, origin_row_key=origin_row_key, origin_user_id=origin_user_id,
)
db.add(entry)
db.flush()
result["entry_id"] = entry.id
result["message"] = f"Entry created for '{source_term}' -> '{corrected_target_term}'"
db.commit()
logger.reflect("Correction processed", result)
return result
# endregion submit_correction
# region submit_bulk_corrections [TYPE Function]
# @PURPOSE: Submit multiple term corrections atomically.
@staticmethod
def submit_bulk_corrections(
db: Session,
dict_id: str,
corrections: list[dict[str, Any]],
origin_user_id: str | None = None,
) -> dict[str, Any]:
with belief_scope("DictionaryCorrectionService.submit_bulk_corrections"):
dictionary = db.query(TerminologyDictionary).filter(TerminologyDictionary.id == dict_id).first()
if not dictionary:
raise ValueError(f"Dictionary '{dict_id}' not found")
results: list[dict[str, Any]] = []
conflicts: list[dict[str, Any]] = []
all_ok = True
for corr in corrections:
source_term = corr.get("source_term", "").strip()
corrected_target = corr.get("corrected_target_term", "").strip()
if not source_term or not corrected_target:
results.append({"source_term": source_term, "action": "error", "message": "source_term and corrected_target_term are required"})
all_ok = False
continue
normalized = _normalize_term(source_term)
bulk_src_lang = "und"
bulk_tgt_lang = "und"
existing = (
db.query(DictionaryEntry)
.filter(
DictionaryEntry.dictionary_id == dict_id,
DictionaryEntry.source_term_normalized == normalized,
or_(
(DictionaryEntry.source_language == bulk_src_lang) & (DictionaryEntry.target_language == bulk_tgt_lang),
(DictionaryEntry.source_language == "und") & (DictionaryEntry.target_language == "und"),
),
)
.first()
)
if existing:
on_conflict = corr.get("on_conflict", "overwrite")
if on_conflict == "keep_existing":
conflicts.append({"source_term": source_term, "existing_target_term": existing.target_term, "submitted_target_term": corrected_target, "action": "keep_existing"})
results.append({"source_term": source_term, "action": "conflict_detected", "message": f"Existing entry kept: '{existing.target_term}'"})
continue
elif on_conflict == "overwrite":
existing.target_term = corrected_target
existing.origin_user_id = origin_user_id
results.append({"source_term": source_term, "action": "updated", "entry_id": existing.id, "message": f"Updated to '{corrected_target}'"})
else:
conflicts.append({"source_term": source_term, "existing_target_term": existing.target_term, "submitted_target_term": corrected_target, "action": "cancel"})
results.append({"source_term": source_term, "action": "skipped", "message": "Cancelled by conflict mode"})
else:
entry = DictionaryEntry(
dictionary_id=dict_id, source_term=source_term, source_term_normalized=normalized,
target_term=corrected_target, source_language=bulk_src_lang, target_language=bulk_tgt_lang,
origin_run_id=corr.get("origin_run_id"), origin_row_key=corr.get("origin_row_key"),
origin_user_id=origin_user_id,
)
db.add(entry)
results.append({"source_term": source_term, "action": "created", "message": f"Entry created for '{source_term}' -> '{corrected_target}'"})
if conflicts and not all_ok:
db.rollback()
return {"status": "conflicts", "results": results, "conflicts": conflicts, "message": "Conflicts detected. Resolve before retrying."}
db.commit()
return {
"status": "completed", "results": results, "conflicts": conflicts,
"total": len(corrections), "applied": sum(1 for r in results if r["action"] in ("created", "updated")),
}
# endregion submit_bulk_corrections
# #endregion DictionaryCorrectionService