refactor(semantics): migrate TIER system to adaptive COMPLEXITY 1-5 scale

- Replaced rigid TIERs with continuous COMPLEXITY 1-5 scale in semantics.md
- Updated generate_semantic_map.py to parse and score based on Complexity
- Added backward compatibility mapping for legacy TIERs
- Migrated all .ai/shots examples to use @COMPLEXITY and updated relation syntax
- Added trivial_utility.py shot to demonstrate implicit Complexity 1 token savings
This commit is contained in:
2026-03-16 09:54:13 +03:00
parent 54e90b589b
commit 321e0eb2db
7 changed files with 236 additions and 124 deletions

View File

@@ -1,10 +1,9 @@
#[DEF:BackendRouteShot:Module]
# @TIER: STANDARD
# @COMPLEXITY: 3
# @SEMANTICS: Route, Task, API, Async
# @PURPOSE: Reference implementation of a task-based route using GRACE-Poly.
# @LAYER: Interface (API)
# @RELATION: IMPLEMENTS -> [DEF:Std:API_FastAPI]
# @INVARIANT: TaskManager must be available in dependency graph.
# @RELATION: [IMPLEMENTS] ->[API_FastAPI]
from typing import Dict, Any
from fastapi import APIRouter, Depends, HTTPException, status
@@ -25,15 +24,13 @@ class CreateTaskRequest(BaseModel):
# [/DEF:CreateTaskRequest:Class]
# [DEF:create_task:Function]
# @COMPLEXITY: 4
# @PURPOSE: Create and start a new task using TaskManager. Non-blocking.
# @DATA_CONTRACT: Input -> CreateTaskRequest, Output -> Task
# @RELATION: [CALLS] ->[task_manager.create_task]
# @PRE: plugin_id must match a registered plugin.
# @POST: A new task is spawned; Task object returned immediately.
# @SIDE_EFFECT: Writes to DB, Triggers background worker.
#
# @UX_STATE: Success -> 201 Created
# @UX_STATE: Error(Validation) -> 400 Bad Request
# @UX_STATE: Error(System) -> 500 Internal Server Error
# @DATA_CONTRACT: Input -> CreateTaskRequest, Output -> Task
@router.post("/tasks", response_model=Task, status_code=status.HTTP_201_CREATED)
async def create_task(
request: CreateTaskRequest,

View File

@@ -1,9 +1,9 @@
# [DEF:TransactionCore:Module]
# @TIER: CRITICAL
# @COMPLEXITY: 5
# @SEMANTICS: Finance, ACID, Transfer, Ledger
# @PURPOSE: Core banking transaction processor with ACID guarantees.
# @LAYER: Domain (Core)
# @RELATION: DEPENDS_ON -> [DEF:Infra:PostgresDB]
# @RELATION: [DEPENDS_ON] ->[PostgresDB]
#
# @INVARIANT: Total system balance must remain constant (Double-Entry Bookkeeping).
# @INVARIANT: Negative transfers are strictly forbidden.
@@ -33,14 +33,13 @@ class TransferResult(NamedTuple):
new_balance: Decimal
# [DEF:execute_transfer:Function]
# @COMPLEXITY: 5
# @PURPOSE: Atomically move funds between accounts with audit trails.
# @DATA_CONTRACT: Input -> (sender_id: str, receiver_id: str, amount: Decimal), Output -> TransferResult
# @RELATION: [CALLS] ->[atomic_transaction]
# @PRE: amount > 0; sender != receiver; sender_balance >= amount.
# @POST: sender_balance -= amount; receiver_balance += amount; Audit Record Created.
# @SIDE_EFFECT: Database mutation (Rows locked), Audit IO.
#
# @UX_STATE: Success -> Returns 200 OK + Transaction Receipt.
# @UX_STATE: Error(LowBalance) -> 422 Unprocessable -> UI shows "Top-up needed" modal.
# @DATA_CONTRACT: Input -> (sender_id: str, receiver_id: str, amount: Decimal), Output -> TransferResult
def execute_transfer(sender_id: str, receiver_id: str, amount: Decimal) -> TransferResult:
# Guard: Input Validation (Вне belief_scope, так как это trivial проверка)
if amount <= Decimal("0.00"):
@@ -54,7 +53,6 @@ def execute_transfer(sender_id: str, receiver_id: str, amount: Decimal) -> Trans
logger.reason("Initiating transfer", extra={"from": sender_id, "to": receiver_id, "amount": amount})
try:
# @RELATION: CALLS -> atomic_transaction
with atomic_transaction():
current_balance = get_balance(sender_id, for_update=True)

View File

@@ -1,18 +1,27 @@
<!-- [DEF:FrontendComponentShot:Component] -->
<!--
/**
* @TIER: CRITICAL
* @COMPLEXITY: 5
* @SEMANTICS: Task, Button, Action, UX
* @PURPOSE: Action button to spawn a new task with full UX feedback cycle.
* @LAYER: UI (Presentation)
* @RELATION: CALLS -> postApi
* @RELATION: [CALLS] ->[postApi]
*
* @INVARIANT: Must prevent double-submission while loading.
* @INVARIANT: Loading state must always terminate (no infinite spinner).
* @INVARIANT: User must receive feedback on both success and failure.
*
* @SIDE_EFFECT: Sends network request and emits toast notifications.
* @DATA_CONTRACT: Input -> { plugin_id: string, params: object }, Output -> { task_id?: string }
*
* @UX_REACTIVITY: Props -> $props(), LocalState -> $state(isLoading).
*
* @UX_STATE: Idle -> Button enabled, primary color, no spinner.
* @UX_STATE: Loading -> Button disabled, spinner visible, aria-busy=true.
* @UX_STATE: Success -> Toast success displayed.
* @UX_STATE: Error -> Toast error displayed.
* @UX_FEEDBACK: toast.success, toast.error
* @UX_RECOVERY: Error -> Keep form interactive and allow retry after failure.
*
* @TEST_CONTRACT: ComponentState ->
* {
* required_fields: { isLoading: bool },
@@ -21,26 +30,13 @@
* "isLoading=true implies aria-busy=true"
* ]
* }
*
* @TEST_FIXTURE: idle_state -> { isLoading: false }
* @TEST_FIXTURE: successful_response -> { task_id: "task_123" }
*
* @TEST_EDGE: api_failure -> raises Error("Network")
* @TEST_EDGE: empty_response -> {}
* @TEST_EDGE: rapid_double_click -> special: concurrent_click
*
* @TEST_INVARIANT: prevent_double_submission -> VERIFIED_BY:[rapid_double_click]
* @TEST_INVARIANT: feedback_always_emitted -> VERIFIED_BY:[successful_response, api_failure]
*
* @UX_STATE: Idle -> Button enabled, primary color, no spinner.
* @UX_STATE: Loading -> Button disabled, spinner visible, aria-busy=true.
* @UX_STATE: Success -> Toast success displayed.
* @UX_STATE: Error -> Toast error displayed.
*
* @UX_FEEDBACK: toast.success, toast.error
*
* @UX_TEST: Idle -> {click: spawnTask, expected: isLoading=true}
* @UX_TEST: Loading -> {double_click: ignored, expected: single_api_call}
*/
-->
<script>

View File

@@ -1,10 +1,9 @@
# [DEF:PluginExampleShot:Module]
# @TIER: STANDARD
# @COMPLEXITY: 3
# @SEMANTICS: Plugin, Core, Extension
# @PURPOSE: Reference implementation of a plugin following GRACE standards.
# @LAYER: Domain (Business Logic)
# @RELATION: INHERITS -> PluginBase
# @INVARIANT: get_schema must return valid JSON Schema.
# @RELATION: [INHERITS] ->[PluginBase]
from typing import Dict, Any, Optional
from ..core.plugin_base import PluginBase
@@ -14,6 +13,7 @@ from ..core.logger import logger, belief_scope
# [DEF:ExamplePlugin:Class]
# @PURPOSE: A sample plugin to demonstrate execution context and logging.
# @RELATION: [INHERITS] ->[PluginBase]
class ExamplePlugin(PluginBase):
@property
def id(self) -> str:
@@ -21,7 +21,6 @@ class ExamplePlugin(PluginBase):
#[DEF:get_schema:Function]
# @PURPOSE: Defines input validation schema.
# @DATA_CONTRACT: Input -> None, Output -> Dict (JSON Schema draft 7)
def get_schema(self) -> Dict[str, Any]:
return {
"type": "object",
@@ -36,8 +35,9 @@ class ExamplePlugin(PluginBase):
#[/DEF:get_schema:Function]
# [DEF:execute:Function]
# @COMPLEXITY: 4
# @PURPOSE: Core plugin logic with structured logging and scope isolation.
# @DATA_CONTRACT: Input -> (params: Dict, context: Optional[TaskContext]), Output -> None
# @RELATION: [BINDS_TO] ->[context.logger]
# @PRE: params must be validated against get_schema() before calling.
# @POST: Plugin payload is processed; progress is reported if context exists.
# @SIDE_EFFECT: Emits logs to centralized system and TaskContext.

View File

@@ -0,0 +1,40 @@
# [DEF:TrivialUtilityShot:Module]
# @COMPLEXITY: 1
# @PURPOSE: Reference implementation of a zero-overhead utility using implicit Complexity 1.
import re
from datetime import datetime, timezone
from typing import Optional
# [DEF:slugify:Function]
# @PURPOSE: Converts a string to a URL-safe slug.
def slugify(text: str) -> str:
if not text:
return ""
text = text.lower().strip()
text = re.sub(r'[^\w\s-]', '', text)
return re.sub(r'[-\s]+', '-', text)
# [/DEF:slugify:Function]
# [DEF:get_utc_now:Function]
def get_utc_now() -> datetime:
"""Returns current UTC datetime (purpose is omitted because it's obvious)."""
return datetime.now(timezone.utc)
# [/DEF:get_utc_now:Function]
# [DEF:PaginationDTO:Class]
class PaginationDTO:
# [DEF:__init__:Function]
def __init__(self, page: int = 1, size: int = 50):
self.page = max(1, page)
self.size = min(max(1, size), 1000)
# [/DEF:__init__:Function]
# [DEF:offset:Function]
@property
def offset(self) -> int:
return (self.page - 1) * self.size
# [/DEF:offset:Function]
# [/DEF:PaginationDTO:Class]
# [/DEF:TrivialUtilityShot:Module]

View File

@@ -30,7 +30,7 @@
## III. ТОПОЛОГИЯ ФАЙЛА (СТРОГИЙ ПОРЯДОК)
1. **HEADER (Заголовок):**[DEF:filename:Module]
@TIER: [CRITICAL | STANDARD | TRIVIAL]
@COMPLEXITY: [1|2|3|4|5] *(алиас: `@C:`; legacy `@TIER` допустим только для обратной совместимости)*
@SEMANTICS: [keywords]
@PURPOSE: [Однострочная суть]
@LAYER: [Domain | UI | Infra]
@@ -40,7 +40,7 @@
3. **FOOTER (Подвал):** [/DEF:filename:Module]
## IV. КОНТРАКТЫ (DESIGN BY CONTRACT & UX)
Обязательны для TIER: CRITICAL и STANDARD. Заменяют стандартные Docstrings.
Контракты требуются адаптивно по уровню сложности, а не по жесткому tier.
**[CORE CONTRACTS]:**
- `@PURPOSE:` Суть функции/компонента.
@@ -62,11 +62,40 @@
- `@TEST_EDGE: [Название] ->[Сбой]` (Минимум 3: missing_field, invalid_type, external_fail).
- `@TEST_INVARIANT: [Имя] -> VERIFIED_BY: [scenario_1, ...]`
## V. УРОВНИ СТРОГОСТИ (TIERS)
Степень контроля задается в Header.
- **CRITICAL** (Ядро/Деньги/Безопасность): 100% покрытие тегами GRACE. Обязательны: Граф, Инварианты, Логи `logger.reason/reflect`, все `@UX` и `@TEST` теги. Использование `belief_scope` строго обязательно.
- **STANDARD** (Бизнес-логика / Типовые формы): Базовый уровень. Обязательны: `@PURPOSE`, `@UX_STATE`, `@RELATION`, базовое логирование.
- **TRIVIAL** (Утилиты / DTO / Атомы UI): Минимальный каркас. Только якоря `[DEF]...[/DEF]` и `@PURPOSE`.
## V. ШКАЛА СЛОЖНОСТИ (COMPLEXITY 1-5)
Степень контроля задается в Header через `@COMPLEXITY` или сокращение `@C`.
Если тег отсутствует, сущность по умолчанию считается **Complexity 1**. Это сделано специально для экономии токенов и снижения шума на очевидных утилитах.
- **1 — ATOMIC**
- Примеры: DTO, исключения, геттеры, простые утилиты, короткие адаптеры.
- Обязательны только якоря `[DEF]...[/DEF]`.
- `@PURPOSE` желателен, но не обязателен.
- **2 — SIMPLE**
- Примеры: простые helper-функции, небольшие мапперы, UI-атомы.
- Обязателен `@PURPOSE`.
- Остальные контракты опциональны.
- **3 — FLOW**
- Примеры: стандартная бизнес-логика, API handlers, сервисные методы, UI с загрузкой данных.
- Обязательны: `@PURPOSE`, `@RELATION`.
- Для UI дополнительно обязателен `@UX_STATE`.
- **4 — ORCHESTRATION**
- Примеры: сложная координация, работа с I/O, multi-step алгоритмы, stateful pipelines.
- Обязательны: `@PURPOSE`, `@RELATION`, `@PRE`, `@POST`, `@SIDE_EFFECT`.
- Для Python обязателен осмысленный путь логирования через `logger.reason()` / `logger.reflect()` или аналогичный belief-state механизм.
- **5 — CRITICAL**
- Примеры: auth, security, database boundaries, migration core, money-like invariants.
- Обязателен полный контракт: уровень 4 + `@DATA_CONTRACT` + `@INVARIANT`.
- Для UI требуются UX-контракты.
- Использование `belief_scope` строго обязательно.
**Legacy mapping (обратная совместимость):**
- `@TIER: TRIVIAL` -> Complexity 1
- `@TIER: STANDARD` -> Complexity 3
- `@TIER: CRITICAL` -> Complexity 5
## VI. ПРОТОКОЛ ЛОГИРОВАНИЯ (THREAD-LOCAL BELIEF STATE)
Логирование — это механизм трассировки рассуждений ИИ (CoT) и управления Attention Energy. Архитектура использует Thread-local storage (`_belief_state`), поэтому `ID` прокидывается автоматически.
@@ -90,11 +119,11 @@
## VII. АЛГОРИТМ ИСПОЛНЕНИЯ И САМОКОРРЕКЦИИ
**[PHASE_1: ANALYSIS]**
Оцени TIER, Layer и UX-требования. При слепоте контекста -> `yield [NEED_CONTEXT: id]`.
Оцени Complexity, Layer и UX-требования. При слепоте контекста -> `yield [NEED_CONTEXT: id]`.
**[PHASE_2: SYNTHESIS]**
Сгенерируй каркас из `[DEF]`, Header и Контрактов.
Сгенерируй каркас из `[DEF]`, Header и только тех контрактов, которые соответствуют уровню сложности.
**[PHASE_3: IMPLEMENTATION]**
Напиши код строго по Контракту. Для CRITICAL секций открой `with belief_scope("ID"):` и орошай путь вызовами `logger.reason()` и `logger.reflect()`.
Напиши код строго по Контракту. Для Complexity 5 секций открой `with belief_scope("ID"):` и орошай путь вызовами `logger.reason()` и `logger.reflect()`.
**[PHASE_4: CLOSURE]**
Убедись, что все `[DEF]` закрыты соответствующими `[/DEF]`.

View File

@@ -19,7 +19,7 @@ import json
import datetime
import fnmatch
import argparse
from enum import Enum
from enum import Enum, IntEnum
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Any, Pattern, Tuple, Set
@@ -59,13 +59,24 @@ class belief_scope:
class Tier(Enum):
# [DEF:Tier:Class]
# @TIER: TRIVIAL
# @PURPOSE: Enumeration of semantic tiers defining validation strictness.
# @PURPOSE: Legacy tier buckets retained for backward-compatible reporting.
CRITICAL = "CRITICAL"
STANDARD = "STANDARD"
TRIVIAL = "TRIVIAL"
# [/DEF:Tier:Class]
class Complexity(IntEnum):
# [DEF:Complexity:Class]
# @PURPOSE: Adaptive semantic complexity scale used for validation strictness.
ONE = 1
TWO = 2
THREE = 3
FOUR = 4
FIVE = 5
# [/DEF:Complexity:Class]
class Severity(Enum):
# [DEF:Severity:Class]
# @TIER: TRIVIAL
@@ -95,31 +106,53 @@ OUTPUT_COMPRESSED_MD = ".ai/PROJECT_MAP.md"
OUTPUT_MODULE_MAP_MD = ".ai/MODULE_MAP.md"
REPORTS_DIR = "semantics/reports"
# Tier-based mandatory tags aligned with .ai/standards/semantics.md
TIER_MANDATORY_TAGS = {
Tier.CRITICAL: {
"Module": ["PURPOSE", "LAYER", "SEMANTICS", "TIER", "INVARIANT", "RELATION"],
"Component": ["PURPOSE", "LAYER", "SEMANTICS", "TIER", "INVARIANT", "RELATION", "UX_STATE", "UX_FEEDBACK", "UX_RECOVERY", "UX_REACTIVITY"],
"Function": ["PURPOSE", "PRE", "POST", "SIDE_EFFECT", "DATA_CONTRACT", "TEST_CONTRACT", "TEST_SCENARIO", "TEST_FIXTURE", "TEST_EDGE", "TEST_INVARIANT"],
"Class": ["PURPOSE", "TIER", "INVARIANT"],
"Store": ["PURPOSE", "TIER", "INVARIANT"],
"Block": ["PURPOSE", "TIER"]
# Complexity-based mandatory tags aligned with .ai/standards/semantics.md
LEGACY_TIER_TO_COMPLEXITY = {
"TRIVIAL": Complexity.ONE,
"STANDARD": Complexity.THREE,
"CRITICAL": Complexity.FIVE,
}
COMPLEXITY_MANDATORY_TAGS = {
Complexity.ONE: {
"Module": [],
"Component": [],
"Function": [],
"Class": [],
"Store": [],
"Block": []
},
Tier.STANDARD: {
"Module": ["PURPOSE", "LAYER", "SEMANTICS", "TIER", "RELATION"],
"Component": ["PURPOSE", "LAYER", "SEMANTICS", "TIER", "RELATION", "UX_STATE", "UX_REACTIVITY"],
"Function": ["PURPOSE", "PRE", "POST", "SIDE_EFFECT", "DATA_CONTRACT"],
"Class": ["PURPOSE", "TIER"],
"Store": ["PURPOSE", "TIER"],
"Block": ["PURPOSE"]
},
Tier.TRIVIAL: {
Complexity.TWO: {
"Module": ["PURPOSE"],
"Component": ["PURPOSE"],
"Function": ["PURPOSE"],
"Class": ["PURPOSE"],
"Store": ["PURPOSE"],
"Block": ["PURPOSE"]
},
Complexity.THREE: {
"Module": ["PURPOSE", "LAYER", "SEMANTICS", "RELATION"],
"Component": ["PURPOSE", "RELATION", "UX_STATE"],
"Function": ["PURPOSE", "RELATION"],
"Class": ["PURPOSE", "RELATION"],
"Store": ["PURPOSE", "RELATION"],
"Block": ["PURPOSE"]
},
Complexity.FOUR: {
"Module": ["PURPOSE", "LAYER", "SEMANTICS", "RELATION", "PRE", "POST", "SIDE_EFFECT"],
"Component": ["PURPOSE", "RELATION", "UX_STATE", "UX_REACTIVITY", "SIDE_EFFECT"],
"Function": ["PURPOSE", "RELATION", "PRE", "POST", "SIDE_EFFECT"],
"Class": ["PURPOSE", "RELATION", "PRE", "POST", "SIDE_EFFECT"],
"Store": ["PURPOSE", "RELATION", "PRE", "POST", "SIDE_EFFECT"],
"Block": ["PURPOSE", "SIDE_EFFECT"]
},
Complexity.FIVE: {
"Module": ["PURPOSE", "LAYER", "SEMANTICS", "RELATION", "INVARIANT", "PRE", "POST", "SIDE_EFFECT", "DATA_CONTRACT"],
"Component": ["PURPOSE", "RELATION", "INVARIANT", "UX_STATE", "UX_FEEDBACK", "UX_RECOVERY", "UX_REACTIVITY", "SIDE_EFFECT", "DATA_CONTRACT"],
"Function": ["PURPOSE", "RELATION", "PRE", "POST", "SIDE_EFFECT", "DATA_CONTRACT"],
"Class": ["PURPOSE", "RELATION", "INVARIANT", "PRE", "POST", "SIDE_EFFECT", "DATA_CONTRACT"],
"Store": ["PURPOSE", "RELATION", "INVARIANT", "PRE", "POST", "SIDE_EFFECT", "DATA_CONTRACT"],
"Block": ["PURPOSE", "SIDE_EFFECT"]
}
}
@@ -127,11 +160,13 @@ ALLOWED_RELATION_PREDICATES = {
"DEPENDS_ON", "CALLS", "INHERITS", "IMPLEMENTS", "DISPATCHES", "BINDS_TO"
}
# Tier-based belief state requirements
TIER_BELIEF_REQUIRED = {
Tier.CRITICAL: True,
Tier.STANDARD: True,
Tier.TRIVIAL: False
# Complexity-based belief state requirements
COMPLEXITY_BELIEF_REQUIRED = {
Complexity.ONE: False,
Complexity.TWO: False,
Complexity.THREE: False,
Complexity.FOUR: True,
Complexity.FIVE: True,
}
# [/SECTION]
@@ -157,7 +192,7 @@ class ComplianceIssue:
# [DEF:SemanticEntity:Class]
# @TIER: CRITICAL
# @PURPOSE: Represents a code entity (Module, Function, Component) found during parsing.
# @INVARIANT: start_line is always set; end_line is set upon closure; tier defaults to STANDARD.
# @INVARIANT: start_line is always set; end_line is set upon closure; complexity defaults to 1 unless explicitly raised.
class SemanticEntity:
# [DEF:__init__:Function]
# @TIER: STANDARD
@@ -187,18 +222,26 @@ class SemanticEntity:
self.has_runes: bool = False
# [/DEF:__init__:Function]
# [DEF:get_tier:Function]
# @TIER: STANDARD
# @PURPOSE: Returns the tier of the entity, defaulting to STANDARD.
# @PRE: tags dictionary is accessible.
# @POST: Returns Tier enum value.
def get_tier(self) -> Tier:
with belief_scope("get_tier"):
tier_str = self.tags.get("TIER", "STANDARD").upper()
try:
base_tier = Tier(tier_str)
except ValueError:
base_tier = Tier.STANDARD
# [DEF:has_explicit_complexity:Function]
# @PURPOSE: Returns whether the entity explicitly declares complexity metadata.
def has_explicit_complexity(self) -> bool:
return any(tag.upper() in {"COMPLEXITY", "C", "TIER"} for tag in self.tags)
# [DEF:get_complexity:Function]
# @PURPOSE: Returns effective complexity with backward compatibility for legacy tiers.
# @PRE: tags dictionary is accessible.
# @POST: Returns Complexity enum value.
def get_complexity(self) -> Complexity:
with belief_scope("get_complexity"):
complexity_value = self.tags.get("COMPLEXITY") or self.tags.get("C")
if complexity_value is not None:
try:
base_complexity = Complexity(int(str(complexity_value).strip()))
except (ValueError, TypeError):
base_complexity = Complexity.ONE
else:
legacy_tier = str(self.tags.get("TIER", "")).upper().strip()
base_complexity = LEGACY_TIER_TO_COMPLEXITY.get(legacy_tier, Complexity.ONE)
file_path_lower = self.file_path.lower()
is_test_entity = (
@@ -207,36 +250,44 @@ class SemanticEntity:
or self.name.startswith("test_")
)
# 1. Tests should never be higher than STANDARD
if is_test_entity and base_tier == Tier.CRITICAL:
return Tier.STANDARD
if is_test_entity and base_complexity > Complexity.THREE:
base_complexity = Complexity.THREE
# 2. Non-route Svelte entities should not be escalated beyond STANDARD by path heuristics.
if self.file_path.endswith(".svelte"):
is_route_level_svelte = any(
marker in self.name for marker in ["+page", "+layout", "Page", "Layout"]
)
if not is_route_level_svelte and base_tier == Tier.CRITICAL:
return Tier.STANDARD
if not is_route_level_svelte and base_complexity > Complexity.THREE:
base_complexity = Complexity.THREE
# 3. Tooling scripts should not be escalated beyond STANDARD.
if ("scripts/" in self.file_path or "_tui.py" in self.file_path) and base_tier == Tier.CRITICAL:
return Tier.STANDARD
if ("scripts/" in self.file_path or "_tui.py" in self.file_path) and base_complexity > Complexity.THREE:
base_complexity = Complexity.THREE
# 4. Promote only module-like entities in critical domains by path heuristic.
# This prevents path segments like "migration" from forcing every nested
# Block/Function/Component in a route file into CRITICAL validation.
critical_keywords = ["auth", "security", "jwt", "database", "migration", "config", "session"]
module_like_types = {"Module", "Class", "Store"}
if (
self.type in module_like_types
not self.has_explicit_complexity()
and self.type in module_like_types
and any(keyword in file_path_lower for keyword in critical_keywords)
and not is_test_entity
and base_tier != Tier.TRIVIAL
):
return Tier.CRITICAL
return Complexity.FIVE
return base_tier
return base_complexity
# [DEF:get_tier:Function]
# @TIER: STANDARD
# @PURPOSE: Returns legacy tier bucket derived from effective complexity.
# @PRE: tags dictionary is accessible.
# @POST: Returns Tier enum value.
def get_tier(self) -> Tier:
with belief_scope("get_tier"):
complexity = self.get_complexity()
if complexity >= Complexity.FIVE:
return Tier.CRITICAL
if complexity >= Complexity.THREE:
return Tier.STANDARD
return Tier.TRIVIAL
# [/DEF:get_tier:Function]
# [DEF:to_dict:Function]
@@ -249,6 +300,7 @@ class SemanticEntity:
result = {
"name": self.name,
"type": self.type,
"complexity": int(self.get_complexity()),
"tier": self.get_tier().value,
"start_line": self.start_line,
"end_line": self.end_line,
@@ -272,15 +324,16 @@ class SemanticEntity:
# [DEF:validate:Function]
# @TIER: CRITICAL
# @PURPOSE: Checks for semantic compliance based on TIER requirements.
# @PRE: Entity structure is complete; tier is determined.
# @PURPOSE: Checks for semantic compliance based on complexity requirements.
# @PRE: Entity structure is complete; complexity is determined.
# @POST: Populates self.compliance_issues with severity levels.
# @SIDE_EFFECT: Modifies self.compliance_issues list.
def validate(self):
with belief_scope("validate"):
complexity = self.get_complexity()
tier = self.get_tier()
# 1. Check Closure (required for ALL tiers)
# 1. Check Closure (required for ALL complexity levels)
if self.end_line is None:
self.compliance_issues.append(ComplianceIssue(
f"Unclosed Anchor: [DEF:{self.name}:{self.type}] started at line {self.start_line}",
@@ -288,8 +341,8 @@ class SemanticEntity:
self.start_line
))
# 2. Check Mandatory Tags based on TIER
required = TIER_MANDATORY_TAGS.get(tier, {}).get(self.type, [])
# 2. Check Mandatory Tags based on complexity
required = COMPLEXITY_MANDATORY_TAGS.get(complexity, {}).get(self.type, [])
for req_tag in required:
found = False
if req_tag == "RELATION" and len(self.relations) > 0:
@@ -300,9 +353,9 @@ class SemanticEntity:
found = True
break
if not found:
severity = Severity.ERROR if tier == Tier.CRITICAL else Severity.WARNING
severity = Severity.ERROR if complexity >= Complexity.FOUR else Severity.WARNING
self.compliance_issues.append(ComplianceIssue(
f"Missing Mandatory Tag: @{req_tag} (required for {tier.value} tier)",
f"Missing Mandatory Tag: @{req_tag} (required for complexity {int(complexity)})",
severity,
self.start_line
))
@@ -313,40 +366,39 @@ class SemanticEntity:
if rel_type and rel_type not in ALLOWED_RELATION_PREDICATES:
self.compliance_issues.append(ComplianceIssue(
f"Invalid @RELATION predicate: {rel_type}. Allowed: {', '.join(sorted(ALLOWED_RELATION_PREDICATES))}",
Severity.ERROR if tier == Tier.CRITICAL else Severity.WARNING,
Severity.ERROR if complexity >= Complexity.FOUR else Severity.WARNING,
self.start_line
))
# 4. Check for Belief State Logging based on TIER
# 4. Check for Belief State Logging based on complexity
if self.type == "Function":
belief_required = TIER_BELIEF_REQUIRED.get(tier, False)
belief_required = COMPLEXITY_BELIEF_REQUIRED.get(complexity, False)
if belief_required:
is_python = self.file_path.endswith(".py")
has_belief = self.has_belief_scope if is_python else self.has_console_log
if not has_belief:
# Check if it's a special case (logger.py or mock functions)
if "logger.py" not in self.file_path and "__" not in self.name:
severity = Severity.ERROR if tier == Tier.CRITICAL else Severity.WARNING
severity = Severity.ERROR if complexity >= Complexity.FOUR else Severity.WARNING
log_type = "belief_scope / molecular methods" if is_python else "console.log with [ID][STATE]"
self.compliance_issues.append(ComplianceIssue(
f"Missing Belief State Logging: Function should use {log_type} (required for {tier.value} tier)",
f"Missing Belief State Logging: Function should use {log_type} (required for complexity {int(complexity)})",
severity,
self.start_line
))
# 5. Check for @INVARIANT in CRITICAL tier
if tier == Tier.CRITICAL and self.type in ["Module", "Component", "Class"]:
# 5. Check for @INVARIANT in maximum complexity
if complexity == Complexity.FIVE and self.type in ["Module", "Component", "Class"]:
if "INVARIANT" not in [k.upper() for k in self.tags.keys()]:
self.compliance_issues.append(ComplianceIssue(
f"Missing @INVARIANT tag (required for CRITICAL tier)",
"Missing @INVARIANT tag (required for complexity 5)",
Severity.ERROR,
self.start_line
))
# 6. Validate modern Svelte reactivity protocol
if self.type == "Component" and self.file_path.endswith(".svelte"):
strict_severity = Severity.ERROR if tier == Tier.CRITICAL else Severity.WARNING
strict_severity = Severity.ERROR if complexity >= Complexity.FOUR else Severity.WARNING
if self.has_export_let:
self.compliance_issues.append(ComplianceIssue(
@@ -379,7 +431,7 @@ class SemanticEntity:
# [DEF:get_score:Function]
# @TIER: STANDARD
# @PURPOSE: Calculates a compliance score (0.0 to 1.0) based on tier requirements.
# @PURPOSE: Calculates a compliance score (0.0 to 1.0) based on complexity requirements.
# @PRE: validate() has been called.
# @POST: Returns a float score.
def get_score(self) -> float:
@@ -387,11 +439,11 @@ class SemanticEntity:
if self.end_line is None:
return 0.0
tier = self.get_tier()
complexity = self.get_complexity()
score = 1.0
# Dynamic penalties based on Tier
error_penalty = 0.5 if tier == Tier.CRITICAL else 0.3
# Dynamic penalties based on complexity
error_penalty = 0.5 if complexity >= Complexity.FOUR else 0.3
warning_penalty = 0.15
# Count issues by severity
@@ -403,7 +455,7 @@ class SemanticEntity:
score -= warnings * warning_penalty
# Check mandatory tags
required = TIER_MANDATORY_TAGS.get(tier, {}).get(self.type, [])
required = COMPLEXITY_MANDATORY_TAGS.get(complexity, {}).get(self.type, [])
if required:
found_count = 0
for req_tag in required:
@@ -687,7 +739,7 @@ def parse_file(full_path: str, rel_path: str, lang: str) -> Tuple[List[SemanticE
# Create orphan function entity
orphan = SemanticEntity(func_name, "Function", lineno, rel_path)
orphan.tags["PURPOSE"] = f"Auto-detected function (orphan)"
orphan.tags["TIER"] = "TRIVIAL"
orphan.tags["COMPLEXITY"] = "1"
orphan.end_line = lineno # Mark as closed immediately
orphan_functions.append(orphan)
@@ -770,7 +822,7 @@ def parse_file(full_path: str, rel_path: str, lang: str) -> Tuple[List[SemanticE
rel_path
)
synthetic_module.tags["PURPOSE"] = f"Auto-generated module for {rel_path}"
synthetic_module.tags["TIER"] = "TRIVIAL"
synthetic_module.tags["COMPLEXITY"] = "1"
synthetic_module.tags["LAYER"] = "Unknown"
synthetic_module.end_line = len(lines)