# [DEF:generate_semantic_map:Module] # @PURPOSE: Scans the codebase to generate a Semantic Map, Module Map, and Compliance Report based on the System Standard. # @PRE: Valid directory containing code to scan. # @POST: Files map.json, .ai/PROJECT_MAP.md, .ai/MODULE_MAP.md, and compliance reports generated. # @TIER: STANDARD # @SEMANTICS: semantic_analysis, parser, map_generator, compliance_checker, tier_validation, svelte_props, data_flow, module_map # @LAYER: DevOps/Tooling # @INVARIANT: All DEF anchors must have matching closing anchors; TIER determines validation strictness. # @RELATION: READS -> FileSystem # @RELATION: PRODUCES -> semantics/semantic_map.json # @RELATION: PRODUCES -> .ai/PROJECT_MAP.md # @RELATION: PRODUCES -> .ai/MODULE_MAP.md # @RELATION: PRODUCES -> semantics/reports/semantic_report_*.md # [SECTION: IMPORTS] import os import re import json import datetime import fnmatch import argparse from enum import Enum, IntEnum from dataclasses import dataclass, field from typing import Dict, List, Optional, Any, Pattern, Tuple, Set # Mock belief_scope for the script itself to avoid import issues class belief_scope: # [DEF:__init__:Function] # @TIER: TRIVIAL # @PURPOSE: Mock init for self-containment. # @PRE: name is a string. # @POST: Instance initialized. def __init__(self, name): self.name = name # [/DEF:__init__:Function] # [DEF:__enter__:Function] # @TIER: TRIVIAL # @RELATION: [DEPENDS_ON] builtin # @PURPOSE: Mock enter. # @PRE: Instance initialized. # @POST: Returns self. def __enter__(self): return self # [/DEF:__enter__:Function] # [DEF:__exit__:Function] # @TIER: TRIVIAL # @RELATION: [DEPENDS_ON] builtin # @PURPOSE: Mock exit. # @PRE: Context entered. # @POST: Context exited. def __exit__(self, *args): pass # [/DEF:__exit__:Function] # [/SECTION] # [SECTION: CONFIGURATION] class Tier(Enum): # [DEF:Tier:Class] # @TIER: TRIVIAL # @RELATION: [DEPENDS_ON] builtin # @PURPOSE: Legacy tier buckets retained for backward-compatible reporting. CRITICAL = "CRITICAL" STANDARD = "STANDARD" TRIVIAL = "TRIVIAL" # [/DEF:Tier:Class] class Complexity(IntEnum): # [DEF:Complexity:Class] # @RELATION: [DEPENDS_ON] builtin # @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 # @RELATION: [DEPENDS_ON] builtin # @PURPOSE: Severity levels for compliance issues. ERROR = "ERROR" WARNING = "WARNING" INFO = "INFO" # [/DEF:Severity:Class] PROJECT_ROOT = "." IGNORE_DIRS = { ".git", "__pycache__", "node_modules", "venv", ".pytest_cache", ".kilocode", "backups", "logs", "semantics", "specs", ".venv" } IGNORE_FILES = { "package-lock.json", "poetry.lock", "yarn.lock" } IGNORE_PATH_PREFIXES = { ".ai/shots/" } IGNORE_EXACT_PATHS = { ".ai/shots" } OUTPUT_JSON = "semantics/semantic_map.json" OUTPUT_COMPRESSED_MD = ".ai/PROJECT_MAP.md" OUTPUT_MODULE_MAP_MD = ".ai/MODULE_MAP.md" REPORTS_DIR = "semantics/reports" # 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": [] }, 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"] } } ALLOWED_RELATION_PREDICATES = { "DEPENDS_ON", "CALLS", "INHERITS", "IMPLEMENTS", "DISPATCHES", "BINDS_TO" } # Complexity-based belief state requirements COMPLEXITY_BELIEF_REQUIRED = { Complexity.ONE: False, Complexity.TWO: False, Complexity.THREE: False, Complexity.FOUR: True, Complexity.FIVE: True, } # [/SECTION] # [DEF:ComplianceIssue:Class] # @TIER: TRIVIAL # @RELATION: [DEPENDS_ON] builtin # @PURPOSE: Represents a single compliance issue with severity. @dataclass class ComplianceIssue: message: str severity: Severity line_number: Optional[int] = None def to_dict(self) -> Dict[str, Any]: return { "message": self.message, "severity": self.severity.value, "line_number": self.line_number } # [/DEF:ComplianceIssue:Class] # [DEF:SemanticEntity:Class] # @TIER: CRITICAL # @RELATION: [DEPENDS_ON] builtin # @PURPOSE: Represents a code entity (Module, Function, Component) found during parsing. # @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 # @RELATION: [DEPENDS_ON] builtin # @PURPOSE: Initializes a new SemanticEntity instance. # @PRE: name, type_, start_line, file_path are provided. # @POST: Instance is initialized with default values. def __init__(self, name: str, type_: str, start_line: int, file_path: str): with belief_scope("__init__"): self.name = name self.type = type_ self.start_line = start_line self.end_line: Optional[int] = None self.file_path = file_path self.tags: Dict[str, str] = {} self.relations: List[Dict[str, str]] = [] self.children: List['SemanticEntity'] = [] self.parent: Optional['SemanticEntity'] = None self.compliance_issues: List[ComplianceIssue] = [] self.has_belief_scope: bool = False self.has_console_log: bool = False # New fields for enhanced Svelte analysis self.props: List[Dict[str, Any]] = [] self.events: List[str] = [] self.data_flow: List[Dict[str, str]] = [] self.has_export_let: bool = False self.has_reactive_label: bool = False self.has_runes: bool = False # [/DEF:__init__:Function] # [DEF:has_explicit_complexity:Function] # @RELATION: [DEPENDS_ON] builtin # @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] # @RELATION: [DEPENDS_ON] builtin # @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 = ( "test" in file_path_lower or "/__tests__/" in self.file_path or self.name.startswith("test_") ) if is_test_entity and base_complexity > Complexity.THREE: base_complexity = Complexity.THREE 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_complexity > Complexity.THREE: base_complexity = Complexity.THREE if ("scripts/" in self.file_path or "_tui.py" in self.file_path) and base_complexity > Complexity.THREE: base_complexity = Complexity.THREE critical_keywords = ["auth", "security", "jwt", "database", "migration", "config", "session"] module_like_types = {"Module", "Class", "Store"} if ( 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 ): return Complexity.FIVE return base_complexity # [DEF:get_tier:Function] # @TIER: STANDARD # @RELATION: [DEPENDS_ON] builtin # @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] # @TIER: STANDARD # @RELATION: [DEPENDS_ON] builtin # @PURPOSE: Serializes the entity to a dictionary for JSON output. # @PRE: Entity is fully populated. # @POST: Returns a dictionary representation. def to_dict(self) -> Dict[str, Any]: with belief_scope("to_dict"): 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, "tags": self.tags, "relations": self.relations, "children": [c.to_dict() for c in self.children], "compliance": { "valid": len([i for i in self.compliance_issues if i.severity == Severity.ERROR]) == 0, "issues": [i.to_dict() for i in self.compliance_issues], "score": self.get_score() } } if self.props: result["props"] = self.props if self.events: result["events"] = self.events if self.data_flow: result["data_flow"] = self.data_flow return result # [/DEF:to_dict:Function] # [DEF:validate:Function] # @TIER: CRITICAL # @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 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}", Severity.ERROR, self.start_line )) # 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: found = True else: for existing_tag in self.tags: if existing_tag.upper() == req_tag: found = True break if not found: severity = Severity.ERROR if complexity >= Complexity.FOUR else Severity.WARNING self.compliance_issues.append(ComplianceIssue( f"Missing Mandatory Tag: @{req_tag} (required for complexity {int(complexity)})", severity, self.start_line )) # 3. Validate relation predicates against GRACE-Poly allowlist for rel in self.relations: rel_type = rel.get("type", "").upper() 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 complexity >= Complexity.FOUR else Severity.WARNING, self.start_line )) # 4. Check for Belief State Logging based on complexity if self.type == "Function": 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: if "logger.py" not in self.file_path and "__" not in self.name: 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 complexity {int(complexity)})", severity, self.start_line )) # 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( "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 complexity >= Complexity.FOUR else Severity.WARNING if self.has_export_let: self.compliance_issues.append(ComplianceIssue( "Svelte protocol violation: `export let` is forbidden; use `$props()`", strict_severity, self.start_line )) if self.has_reactive_label: self.compliance_issues.append(ComplianceIssue( "Svelte protocol violation: `$:` reactive label is forbidden; use runes `$state/$derived/$effect`", strict_severity, self.start_line )) # 7. Validate module length limit if self.type == "Module" and self.end_line is not None: module_length = self.end_line - self.start_line + 1 if module_length >= 300: self.compliance_issues.append(ComplianceIssue( f"Fractal limit warning: Module length is {module_length} lines (must be < 300)", Severity.WARNING, self.start_line )) # Recursive validation for child in self.children: child.validate() # [/DEF:validate:Function] # [DEF:get_score:Function] # @TIER: STANDARD # @RELATION: [DEPENDS_ON] builtin # @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: with belief_scope("get_score"): if self.end_line is None: return 0.0 complexity = self.get_complexity() score = 1.0 # Dynamic penalties based on complexity error_penalty = 0.5 if complexity >= Complexity.FOUR else 0.3 warning_penalty = 0.15 # Count issues by severity errors = len([i for i in self.compliance_issues if i.severity == Severity.ERROR]) warnings = len([i for i in self.compliance_issues if i.severity == Severity.WARNING]) # Penalties score -= errors * error_penalty score -= warnings * warning_penalty # Check mandatory tags required = COMPLEXITY_MANDATORY_TAGS.get(complexity, {}).get(self.type, []) if required: found_count = 0 for req_tag in required: found = False if req_tag == "RELATION" and len(self.relations) > 0: found = True else: for existing_tag in self.tags: if existing_tag.upper() == req_tag: found_count += 1 found = True break if found_count < len(required): missing_ratio = 1 - (found_count / len(required)) score -= 0.3 * missing_ratio return max(0.0, score) # [/DEF:get_score:Function] # [/DEF:SemanticEntity:Class] # [DEF:get_patterns:Function] # @TIER: STANDARD # @PURPOSE: Returns regex patterns for a specific language. # @PRE: lang is either 'python' or 'svelte_js'. # @POST: Returns a dictionary of compiled regex patterns. # @PARAM: lang (str) - 'python' or 'svelte_js' def get_patterns(lang: str) -> Dict[str, Pattern]: with belief_scope("get_patterns"): if lang == "python": return { "anchor_start": re.compile(r"#\s*\[DEF:(?P[-\w\.]+):(?P\w+)\]"), "anchor_end": re.compile(r"#\s*\[/DEF:(?P[-\w\.]+):(?P\w+)\]"), "tag": re.compile(r"#\s*@(?P[A-Z_]+):\s*(?P.*)"), "relation": re.compile(r"#\s*@RELATION:\s*\[?(?P\w+)\]?\s*->\s*\[?(?P[^\]]+)\]?"), "func_def": re.compile(r"^\s*(async\s+)?def\s+(?P\w+)"), "belief_scope": re.compile(r"with\s+(\w+\.)?belief_scope\(|@believed\("), "molecular_log": re.compile(r"logger\.(explore|reason|reflect)\("), } else: return { "html_anchor_start": re.compile(r""), "html_anchor_end": re.compile(r""), "js_anchor_start": re.compile(r"//\s*\[DEF:(?P[-\w\.]+):(?P\w+)\]"), "js_anchor_end": re.compile(r"//\s*\[/DEF:(?P[-\w\.]+):(?P\w+)\]"), "html_tag": re.compile(r"@(?P[A-Z_]+):\s*(?P.*)"), "jsdoc_tag": re.compile(r"\*\s*@(?P[A-Za-z_]+)\s*:?\s*(?P.*)"), "relation": re.compile(r"(?:|{rel['type']}|{safe_other}\n") break f.write("```\n") print(f"Generated {OUTPUT_MODULE_MAP_MD}") # [/DEF:_generate_module_map:Function] # [/DEF:SemanticMapGenerator:Class] if __name__ == "__main__": parser = argparse.ArgumentParser(description="Generate Semantic Map and Compliance Reports") parser.add_argument("--agent-report", action="store_true", help="Output JSON report for AI agents") args = parser.parse_args() generator = SemanticMapGenerator(PROJECT_ROOT) generator.run() if args.agent_report: generator._print_agent_report() # [/DEF:generate_semantic_map:Module]