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:
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user