semantic update
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
# [DEF:generate_semantic_map:Module]
|
||||
#
|
||||
# @TIER: CRITICAL
|
||||
# @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
|
||||
# @PURPOSE: Scans the codebase to generate a Semantic Map, Module Map, and Compliance Report based on the System Standard.
|
||||
# @LAYER: DevOps/Tooling
|
||||
# @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
|
||||
@@ -262,7 +263,7 @@ class SemanticEntity:
|
||||
# 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
|
||||
log_type = "belief_scope" if is_python else "console.log with [ID][STATE]"
|
||||
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)",
|
||||
severity,
|
||||
@@ -296,13 +297,17 @@ class SemanticEntity:
|
||||
tier = self.get_tier()
|
||||
score = 1.0
|
||||
|
||||
# Dynamic penalties based on Tier
|
||||
error_penalty = 0.5 if tier == Tier.CRITICAL 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 * 0.3
|
||||
score -= warnings * 0.1
|
||||
score -= errors * error_penalty
|
||||
score -= warnings * warning_penalty
|
||||
|
||||
# Check mandatory tags
|
||||
required = TIER_MANDATORY_TAGS.get(tier, {}).get(self.type, [])
|
||||
@@ -314,7 +319,8 @@ class SemanticEntity:
|
||||
found_count += 1
|
||||
break
|
||||
if found_count < len(required):
|
||||
score -= 0.2 * (1 - (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]
|
||||
@@ -336,7 +342,8 @@ def get_patterns(lang: str) -> Dict[str, Pattern]:
|
||||
"tag": re.compile(r"#\s*@(?P<tag>[A-Z_]+):\s*(?P<value>.*)"),
|
||||
"relation": re.compile(r"#\s*@RELATION:\s*(?P<type>\w+)\s*->\s*(?P<target>.*)"),
|
||||
"func_def": re.compile(r"^\s*(async\s+)?def\s+(?P<name>\w+)"),
|
||||
"belief_scope": re.compile(r"with\s+(\w+\.)?belief_scope\("),
|
||||
"belief_scope": re.compile(r"with\s+(\w+\.)?belief_scope\(|@believed\("),
|
||||
"molecular_log": re.compile(r"logger\.(explore|reason|reflect)\("),
|
||||
}
|
||||
else:
|
||||
return {
|
||||
@@ -348,7 +355,7 @@ def get_patterns(lang: str) -> Dict[str, Pattern]:
|
||||
"jsdoc_tag": re.compile(r"\*\s*@(?P<tag>[a-zA-Z]+)\s+(?P<value>.*)"),
|
||||
"relation": re.compile(r"//\s*@RELATION:\s*(?P<type>\w+)\s*->\s*(?P<target>.*)"),
|
||||
"func_def": re.compile(r"^\s*(export\s+)?(async\s+)?function\s+(?P<name>\w+)"),
|
||||
"console_log": re.compile(r"console\.log\s*\(\s*['\"]\[[\w_]+\]\[[\w_]+\]"),
|
||||
"console_log": re.compile(r"console\.log\s*\(\s*['\"`]\[[\w_]+\]\[[A-Za-z0-9_:]+\]"),
|
||||
# Svelte-specific patterns
|
||||
"export_let": re.compile(r"export\s+let\s+(?P<name>\w+)(?:\s*:\s*(?P<type>[\w\[\]|<>]+))?(?:\s*=\s*(?P<default>[^;]+))?"),
|
||||
"create_event_dispatcher": re.compile(r"createEventDispatcher\s*<\s*\{\s*(?P<events>[^}]+)\s*\}\s*\>"),
|
||||
@@ -609,8 +616,10 @@ def parse_file(full_path: str, rel_path: str, lang: str) -> Tuple[List[SemanticE
|
||||
current.tags[tag_name] = tag_value
|
||||
|
||||
# Check for belief scope in implementation
|
||||
if lang == "python" and "belief_scope" in patterns:
|
||||
if patterns["belief_scope"].search(line):
|
||||
if lang == "python":
|
||||
if "belief_scope" in patterns and patterns["belief_scope"].search(line):
|
||||
current.has_belief_scope = True
|
||||
elif "molecular_log" in patterns and patterns["molecular_log"].search(line):
|
||||
current.has_belief_scope = True
|
||||
|
||||
# Check for console.log belief state in Svelte
|
||||
@@ -803,26 +812,39 @@ class SemanticMapGenerator:
|
||||
with belief_scope("_process_file_results"):
|
||||
total_score = 0
|
||||
count = 0
|
||||
module_max_tier = Tier.TRIVIAL
|
||||
|
||||
# [DEF:validate_recursive:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Recursively validates a list of entities.
|
||||
# @PRE: ent_list is a list of SemanticEntity objects.
|
||||
# @POST: All entities and their children are validated.
|
||||
# @PURPOSE: Calculate score and determine module's max tier for weighted global score
|
||||
# @PRE: Entities exist
|
||||
# @POST: Entities are validated
|
||||
def validate_recursive(ent_list):
|
||||
with belief_scope("validate_recursive"):
|
||||
nonlocal total_score, count
|
||||
nonlocal total_score, count, module_max_tier
|
||||
for e in ent_list:
|
||||
e.validate()
|
||||
total_score += e.get_score()
|
||||
count += 1
|
||||
|
||||
# Determine dominant tier for file
|
||||
e_tier = e.get_tier()
|
||||
if e_tier == Tier.CRITICAL:
|
||||
module_max_tier = Tier.CRITICAL
|
||||
elif e_tier == Tier.STANDARD and module_max_tier != Tier.CRITICAL:
|
||||
module_max_tier = Tier.STANDARD
|
||||
|
||||
validate_recursive(e.children)
|
||||
# [/DEF:validate_recursive:Function]
|
||||
|
||||
validate_recursive(entities)
|
||||
|
||||
self.entities.extend(entities)
|
||||
self.file_scores[rel_path] = (total_score / count) if count > 0 else 0.0
|
||||
|
||||
# Store both the score and the dominating tier for weighted global calculation
|
||||
file_score = (total_score / count) if count > 0 else 0.0
|
||||
self.file_scores[rel_path] = {"score": file_score, "tier": module_max_tier}
|
||||
|
||||
# [/DEF:_process_file_results:Function]
|
||||
|
||||
# [DEF:_generate_artifacts:Function]
|
||||
@@ -860,7 +882,19 @@ class SemanticMapGenerator:
|
||||
os.makedirs(REPORTS_DIR, exist_ok=True)
|
||||
|
||||
total_files = len(self.file_scores)
|
||||
avg_score = sum(self.file_scores.values()) / total_files if total_files > 0 else 0
|
||||
|
||||
total_weighted_score = 0
|
||||
total_weight = 0
|
||||
|
||||
for file_path, data in self.file_scores.items():
|
||||
tier = data["tier"]
|
||||
score = data["score"]
|
||||
weight = 3 if tier == Tier.CRITICAL else (2 if tier == Tier.STANDARD else 1)
|
||||
|
||||
total_weighted_score += score * weight
|
||||
total_weight += weight
|
||||
|
||||
avg_score = total_weighted_score / total_weight if total_weight > 0 else 0
|
||||
|
||||
# Count issues by severity
|
||||
error_count = len([i for i in self.global_issues if i.severity == Severity.ERROR])
|
||||
@@ -884,12 +918,19 @@ class SemanticMapGenerator:
|
||||
f.write("| File | Score | Tier | Issues |\n")
|
||||
f.write("|------|-------|------|--------|\n")
|
||||
|
||||
sorted_files = sorted(self.file_scores.items(), key=lambda x: x[1])
|
||||
# Sort logically: Critical first, then by score
|
||||
sorted_files = sorted(self.file_scores.items(), key=lambda x: (
|
||||
0 if x[1]["tier"] == Tier.CRITICAL else (1 if x[1]["tier"] == Tier.STANDARD else 2),
|
||||
x[1]["score"]
|
||||
))
|
||||
|
||||
for file_path, score in sorted_files:
|
||||
for file_path, data in sorted_files:
|
||||
score = data["score"]
|
||||
issues = []
|
||||
tier = "N/A"
|
||||
self._collect_issues(self.entities, file_path, issues, tier)
|
||||
# Override Display Tier with the dominant tier we computed
|
||||
tier = data["tier"].value
|
||||
|
||||
status_icon = "🟢" if score == 1.0 else "🟡" if score > 0.5 else "🔴"
|
||||
issue_text = "<br>".join([f"{'🔴' if i.severity == Severity.ERROR else '🟡'} {i.message}" for i in issues[:3]])
|
||||
@@ -1024,12 +1065,13 @@ class SemanticMapGenerator:
|
||||
# @PRE: file_path is a valid relative path.
|
||||
# @POST: Returns a module path string.
|
||||
def _get_module_path(file_path: str) -> str:
|
||||
# Convert file path to module-like path
|
||||
parts = file_path.replace(os.sep, '/').split('/')
|
||||
# Remove filename
|
||||
if len(parts) > 1:
|
||||
return '/'.join(parts[:-1])
|
||||
return 'root'
|
||||
with belief_scope("_get_module_path"):
|
||||
# Convert file path to module-like path
|
||||
parts = file_path.replace(os.sep, '/').split('/')
|
||||
# Remove filename
|
||||
if len(parts) > 1:
|
||||
return '/'.join(parts[:-1])
|
||||
return 'root'
|
||||
# [/DEF:_get_module_path:Function]
|
||||
|
||||
# [DEF:_collect_all_entities:Function]
|
||||
@@ -1038,9 +1080,10 @@ class SemanticMapGenerator:
|
||||
# @PRE: entity list is valid.
|
||||
# @POST: Returns flat list of all entities with their hierarchy.
|
||||
def _collect_all_entities(entities: List[SemanticEntity], result: List[Tuple[str, SemanticEntity]]):
|
||||
for e in entities:
|
||||
result.append((_get_module_path(e.file_path), e))
|
||||
_collect_all_entities(e.children, result)
|
||||
with belief_scope("_collect_all_entities"):
|
||||
for e in entities:
|
||||
result.append((_get_module_path(e.file_path), e))
|
||||
_collect_all_entities(e.children, result)
|
||||
# [/DEF:_collect_all_entities:Function]
|
||||
|
||||
# Collect all entities
|
||||
|
||||
Reference in New Issue
Block a user