Classify full interpretation source inventory
This commit is contained in:
@@ -26,6 +26,78 @@ REQUIRED_LAYERS = [
|
||||
"quarantined_drafts",
|
||||
]
|
||||
|
||||
SCAN_ROOTS = [
|
||||
"references",
|
||||
"docs",
|
||||
"jyotish-app",
|
||||
"assets",
|
||||
"SKILL.md",
|
||||
"AGENTS.md",
|
||||
]
|
||||
|
||||
EXCLUDED_PARTS = {
|
||||
".git",
|
||||
".pytest_cache",
|
||||
".ruff_cache",
|
||||
"__pycache__",
|
||||
"node_modules",
|
||||
"venv_vedastro",
|
||||
"build",
|
||||
"dist",
|
||||
"scratch",
|
||||
}
|
||||
|
||||
TEXT_EXTENSIONS = {".md", ".txt", ".json", ".js", ".ts", ".tsx", ".jsx", ".html", ".csv"}
|
||||
|
||||
CANDIDATE_KEYWORDS = [
|
||||
"interpret",
|
||||
"解释",
|
||||
"解读",
|
||||
"reading",
|
||||
"reader",
|
||||
"rule",
|
||||
"rules",
|
||||
"规则",
|
||||
"template",
|
||||
"模板",
|
||||
"case",
|
||||
"案例",
|
||||
"bphs",
|
||||
"parashara",
|
||||
"parasara",
|
||||
"raman",
|
||||
"jataka",
|
||||
"saravali",
|
||||
"phaladeepika",
|
||||
"hora",
|
||||
"house",
|
||||
"宫",
|
||||
"lord",
|
||||
"主",
|
||||
"yoga",
|
||||
"saham",
|
||||
"dasha",
|
||||
"transit",
|
||||
"career",
|
||||
"profession",
|
||||
"事业",
|
||||
"wealth",
|
||||
"finance",
|
||||
"财富",
|
||||
"marriage",
|
||||
"relationship",
|
||||
"婚",
|
||||
"关系",
|
||||
"timing",
|
||||
"应期",
|
||||
"event",
|
||||
"预测",
|
||||
"validation",
|
||||
"校验",
|
||||
"qa",
|
||||
"workflow",
|
||||
]
|
||||
|
||||
|
||||
def build_report() -> dict[str, Any]:
|
||||
source_pack = _existing_interpretation_source_pack()
|
||||
@@ -63,6 +135,7 @@ def build_report() -> dict[str, Any]:
|
||||
"summary": summary,
|
||||
"layers": layers,
|
||||
"runtime_source_refs": source_refs,
|
||||
"full_classification": _build_full_classification(source_refs, layers),
|
||||
"failures": failures,
|
||||
"boundary": (
|
||||
"This gate validates explicit source inventory wiring. It does not promote drafts "
|
||||
@@ -71,6 +144,175 @@ def build_report() -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _relative(path: Path) -> str:
|
||||
return str(path.relative_to(ROOT))
|
||||
|
||||
|
||||
def _should_skip(path: Path) -> bool:
|
||||
return any(part in EXCLUDED_PARTS for part in path.parts)
|
||||
|
||||
|
||||
def _iter_candidate_files() -> list[Path]:
|
||||
items: list[Path] = []
|
||||
for root_name in SCAN_ROOTS:
|
||||
root = ROOT / root_name
|
||||
if root.is_file():
|
||||
items.append(root)
|
||||
elif root.exists():
|
||||
items.extend(path for path in root.rglob("*") if path.is_file())
|
||||
return sorted(set(items))
|
||||
|
||||
|
||||
def _is_candidate(path: Path) -> bool:
|
||||
if _should_skip(path) or path.suffix.lower() not in TEXT_EXTENSIONS:
|
||||
return False
|
||||
rel = _relative(path).lower()
|
||||
name = path.name.lower()
|
||||
if any(keyword.lower() in rel or keyword.lower() in name for keyword in CANDIDATE_KEYWORDS):
|
||||
return True
|
||||
if path.stat().st_size > 300_000:
|
||||
return False
|
||||
try:
|
||||
text = path.read_text(encoding="utf-8", errors="ignore")[:4000].lower()
|
||||
except OSError:
|
||||
return False
|
||||
return any(keyword.lower() in text for keyword in CANDIDATE_KEYWORDS)
|
||||
|
||||
|
||||
def _classify_candidate(path: str, runtime_source_refs: set[str], layer_refs: set[str]) -> dict[str, Any]:
|
||||
if path in runtime_source_refs:
|
||||
return {
|
||||
"classification": "runtime_reference_layer",
|
||||
"priority": "runtime",
|
||||
"promotion_status": "already_wired",
|
||||
"reason": "Already exposed through interpretation_source_pack.source_refs.",
|
||||
}
|
||||
if path in layer_refs:
|
||||
return {
|
||||
"classification": "indexed_reference_layer",
|
||||
"priority": "runtime",
|
||||
"promotion_status": "indexed",
|
||||
"reason": "Indexed by the interpretation source inventory.",
|
||||
}
|
||||
if path.startswith("references/real_case_studies/"):
|
||||
return {
|
||||
"classification": "real_case_calibration",
|
||||
"priority": "priority_1",
|
||||
"promotion_status": "reference_layer_candidate",
|
||||
"reason": "Real-case material should be reviewed before confidence calibration claims.",
|
||||
}
|
||||
if path.startswith("references/open_source_sources/rishi-ai-mcp/"):
|
||||
return {
|
||||
"classification": "open_source_reference",
|
||||
"priority": "priority_1",
|
||||
"promotion_status": "reference_layer_candidate",
|
||||
"reason": "User-prioritized open-source skill/workflow corpus; must remain license-aware.",
|
||||
}
|
||||
if path.startswith("references/open_source_sources/vedic-astro-skills/"):
|
||||
return {
|
||||
"classification": "open_source_reference",
|
||||
"priority": "priority_1",
|
||||
"promotion_status": "reference_layer_candidate",
|
||||
"reason": "User-prioritized open-source Jyotish skills corpus; classify before selective reuse.",
|
||||
}
|
||||
if path.startswith("references/open_source_sources/"):
|
||||
return {
|
||||
"classification": "open_source_reference",
|
||||
"priority": "priority_2",
|
||||
"promotion_status": "reference_layer_candidate",
|
||||
"reason": "Open-source reference corpus; classify with license boundary before runtime use.",
|
||||
}
|
||||
if path.startswith("references/oracle/"):
|
||||
return {
|
||||
"classification": "oracle_artifact",
|
||||
"priority": "priority_2",
|
||||
"promotion_status": "oracle_evidence_only",
|
||||
"reason": "External evidence artifact; do not convert into interpretive rule text.",
|
||||
}
|
||||
if path.startswith("references/"):
|
||||
return {
|
||||
"classification": "reference_candidate",
|
||||
"priority": "priority_1",
|
||||
"promotion_status": "reference_layer_candidate",
|
||||
"reason": "Core references directory; review for source-of-truth or reference-layer promotion.",
|
||||
}
|
||||
if path.startswith("docs/research/local_drafts/"):
|
||||
return {
|
||||
"classification": "quarantined_draft",
|
||||
"priority": "priority_3",
|
||||
"promotion_status": "not_truth_source",
|
||||
"reason": "Local draft; index for awareness but do not promote without explicit review.",
|
||||
}
|
||||
if path.startswith("docs/research/"):
|
||||
return {
|
||||
"classification": "research_governance",
|
||||
"priority": "priority_3",
|
||||
"promotion_status": "governance_or_history",
|
||||
"reason": "Research/governance history; useful for audit, not direct interpretation truth.",
|
||||
}
|
||||
if path.startswith("docs/benchmark/") or path.startswith("benchmarks/") or path.startswith("benchmark/"):
|
||||
return {
|
||||
"classification": "benchmark_evidence",
|
||||
"priority": "priority_2",
|
||||
"promotion_status": "benchmark_evidence_only",
|
||||
"reason": "Benchmark or evidence report; use for validation boundaries, not direct rules.",
|
||||
}
|
||||
if path.startswith("jyotish-app/"):
|
||||
return {
|
||||
"classification": "frontend_surface",
|
||||
"priority": "priority_3",
|
||||
"promotion_status": "product_surface",
|
||||
"reason": "Frontend implementation or copy surface; classify separately from source truth.",
|
||||
}
|
||||
if path.startswith("assets/"):
|
||||
return {
|
||||
"classification": "template_asset",
|
||||
"priority": "priority_2",
|
||||
"promotion_status": "template_reference",
|
||||
"reason": "Reusable template asset; can guide output structure but is not a rule source.",
|
||||
}
|
||||
return {
|
||||
"classification": "project_governance",
|
||||
"priority": "priority_3",
|
||||
"promotion_status": "governance_or_history",
|
||||
"reason": "Project-level planning/governance material.",
|
||||
}
|
||||
|
||||
|
||||
def _build_full_classification(source_refs: list[str], layers: dict[str, Any]) -> dict[str, Any]:
|
||||
runtime_source_refs = set(source_refs)
|
||||
layer_refs: set[str] = set()
|
||||
for layer in layers.values():
|
||||
if isinstance(layer, dict):
|
||||
refs = layer.get("source_refs")
|
||||
if isinstance(refs, list):
|
||||
layer_refs.update(str(ref) for ref in refs)
|
||||
|
||||
candidate_paths = [_relative(path) for path in _iter_candidate_files() if _is_candidate(path)]
|
||||
by_path = {
|
||||
path: _classify_candidate(path, runtime_source_refs, layer_refs)
|
||||
for path in candidate_paths
|
||||
}
|
||||
classification_counts: dict[str, int] = {}
|
||||
priority_bucket_counts: dict[str, int] = {}
|
||||
promotion_status_counts: dict[str, int] = {}
|
||||
for item in by_path.values():
|
||||
classification_counts[item["classification"]] = classification_counts.get(item["classification"], 0) + 1
|
||||
priority_bucket_counts[item["priority"]] = priority_bucket_counts.get(item["priority"], 0) + 1
|
||||
promotion_status_counts[item["promotion_status"]] = promotion_status_counts.get(item["promotion_status"], 0) + 1
|
||||
return {
|
||||
"status": "classified",
|
||||
"candidate_count": len(candidate_paths),
|
||||
"classified_candidate_count": len(by_path),
|
||||
"unclassified_candidate_count": 0,
|
||||
"classification_counts": dict(sorted(classification_counts.items())),
|
||||
"priority_bucket_counts": dict(sorted(priority_bucket_counts.items())),
|
||||
"promotion_status_counts": dict(sorted(promotion_status_counts.items())),
|
||||
"by_path": by_path,
|
||||
"boundary": "Classification is a triage map; promotion still requires source review and tests.",
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
report = build_report()
|
||||
print(json.dumps(report, ensure_ascii=False, indent=2))
|
||||
|
||||
Reference in New Issue
Block a user