chore: remove legacy Vite frontend

This commit is contained in:
Jesse_Chen
2026-07-20 10:36:36 +08:00
parent ee353440ed
commit 751237cb32
90 changed files with 141 additions and 40872 deletions
+3 -3
View File
@@ -21,7 +21,7 @@ from typing import Any
ROOT = Path(__file__).resolve().parents[1]
REGISTRY_PATH = ROOT / "references" / "technique_registry.json"
SCRIPTS_DIR = ROOT / "scripts"
APP_DIR = ROOT / "jyotish-app"
APP_DIR = ROOT / "frontend" / "src"
TESTS_DIR = ROOT / "tests"
OPEN_SOURCE_DIR = ROOT / "references" / "open_source_sources"
@@ -135,9 +135,9 @@ def scan_frontend() -> dict[str, Any]:
files: list[str] = []
if APP_DIR.exists():
for path in APP_DIR.rglob("*"):
if any(part in {"node_modules", "dist", ".vite"} for part in path.parts):
if any(part in {"node_modules", ".next"} for part in path.parts):
continue
if path.suffix not in {".js", ".html", ".css"}:
if path.suffix not in {".js", ".ts", ".tsx", ".jsx", ".html", ".css"}:
continue
files.append(str(path.relative_to(ROOT)))
text_parts.append(read_text(path))
-101
View File
@@ -1,101 +0,0 @@
#!/usr/bin/env python3
"""Check ordinary-user delivery paths before publishing a Jyotish build."""
from __future__ import annotations
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
APP = ROOT / "jyotish-app"
def read(path: Path) -> str:
return path.read_text(encoding="utf-8")
def require(condition: bool, label: str, failures: list[str]) -> None:
if not condition:
failures.append(label)
def delivery_matrix() -> list[dict]:
return [
{
"id": "local-dev",
"label": "Local dev",
"user_url": "http://127.0.0.1:5173",
"commands": [
".venv/bin/python scripts/jyotish_api_server.py --host 127.0.0.1 --port 5200",
"cd jyotish-app && npm run dev -- --host 127.0.0.1 --port 5173",
],
"api_required": True,
"scope": "Full web/app user experience with local API.",
},
{
"id": "docker-compose",
"label": "Docker Compose",
"user_url": "http://localhost:5300",
"commands": ["docker compose up -d"],
"api_required": True,
"scope": "Bundled API + web shell for local ordinary-user trials.",
},
{
"id": "static-demo-pwa",
"label": "Static demo / PWA",
"user_url": "https://<static-host>/",
"commands": ["cd jyotish-app && npm run build"],
"api_required": False,
"scope": "public demo shell; full advanced techniques require a local API service.",
},
{
"id": "desktop-shell",
"label": "Desktop shell",
"user_url": "pwa://installed-app or pake://local-url",
"commands": [
"cd jyotish-app && npm run build && npm run preview -- --host 127.0.0.1 --port 4173",
"python3 scripts/desktop_packaging_preflight.py",
],
"api_required": True,
"scope": "PWA/Pake now; Tauri sidecar only after API lifecycle and signing are fixed.",
},
]
def main() -> int:
failures: list[str] = []
readme = read(ROOT / "README.md")
dockerfile = read(ROOT / "Dockerfile")
compose = read(ROOT / "docker-compose.yml")
package = json.loads(read(APP / "package.json"))
manifest = json.loads(read(APP / "public" / "manifest.webmanifest"))
sw = read(APP / "public" / "sw.js")
index_html = read(APP / "index.html")
main_js = read(APP / "main.js")
require("普通用户交付形态" in readme, "README missing ordinary-user delivery matrix", failures)
require("python3 scripts/deployment_preflight.py" in readme, "README missing deployment preflight command", failures)
require("static_demo_boundary_visible" in readme, "README missing static demo boundary marker", failures)
require('id="static-demo-boundary"' in index_html, "static demo capability boundary must be visible on first screen", failures)
require("renderStaticDemoBoundary" in main_js, "Trust Center must render static demo capability boundary", failures)
require("http://localhost:5300" in compose, "docker-compose missing ordinary web URL note", failures)
require("python3 scripts/deployment_preflight.py" in dockerfile, "Dockerfile must run deployment preflight", failures)
require("build" in package.get("scripts", {}), "jyotish-app missing build script", failures)
require("preview" in package.get("scripts", {}), "jyotish-app missing preview script", failures)
require(manifest.get("display") == "standalone", "PWA manifest must remain standalone", failures)
require("url.pathname.startsWith('/api/')" in sw, "service worker must bypass API requests", failures)
result = {
"valid": not failures,
"failures": failures,
"delivery_matrix": delivery_matrix(),
"static_demo_boundary_visible": "static shell is labeled; local API-only capabilities are listed for ordinary users.",
"ordinary_user_note": "公开演示环境只能完整展示静态壳;完整高级技法需要本地 API 服务。",
}
print(json.dumps(result, ensure_ascii=False, indent=2))
return 0 if not failures else 1
if __name__ == "__main__":
raise SystemExit(main())
-147
View File
@@ -1,147 +0,0 @@
#!/usr/bin/env python3
"""Check whether the Jyotish web app is ready for PWA/Pake/Tauri packaging."""
from __future__ import annotations
import json
import re
import shutil
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
APP = ROOT / "jyotish-app"
def read(path: Path) -> str:
return path.read_text(encoding="utf-8")
def require(condition: bool, label: str, failures: list[str]) -> None:
if not condition:
failures.append(label)
def probe_command(binary: str, args: list[str] | None = None) -> dict:
path = shutil.which(binary)
result = {
"binary": binary,
"available": bool(path),
"path": path,
"version": None,
}
if not path:
return result
try:
completed = subprocess.run(
[path, *(args or ["--version"])],
capture_output=True,
text=True,
timeout=4,
check=False,
)
result["version"] = (completed.stdout or completed.stderr).strip().splitlines()[0] if (completed.stdout or completed.stderr).strip() else ""
except Exception as exc:
result["version"] = f"probe_failed: {exc}"
return result
def toolchain_probe() -> dict:
probes = {
"node": probe_command("node"),
"npm": probe_command("npm"),
"rustc": probe_command("rustc"),
"cargo": probe_command("cargo"),
"xcodebuild": probe_command("xcodebuild", ["-version"]),
"pake": probe_command("pake"),
"tauri": probe_command("tauri"),
}
xcode_version = probes["xcodebuild"].get("version") or ""
xcode_ready = bool(probes["xcodebuild"]["available"] and "requires Xcode" not in xcode_version)
return {
"non_destructive": True,
"note": "Probe only checks local CLI presence/version; it does not run npm build, pake, tauri build, signing, notarization, or generate packages.",
"license_gate": {
"pake": "Pake upstream is GPL-3.0; review distribution compatibility before shipping a bundled desktop app.",
"tauri": "Tauri app distribution still needs platform permissions, sidecar lifecycle design, signing_notarization, and Apple Developer decisions on macOS.",
},
"commands": probes,
"readiness": {
"pwa": True,
"pake": bool(probes["node"]["available"] and probes["npm"]["available"] and probes["rustc"]["available"] and probes["cargo"]["available"] and probes["pake"]["available"]),
"tauri": bool(probes["node"]["available"] and probes["npm"]["available"] and probes["rustc"]["available"] and probes["cargo"]["available"] and probes["tauri"]["available"]),
"macos_signing_notarization": xcode_ready,
},
"warnings": [
"xcodebuild exists but full Xcode is not selected; macOS signing_notarization is not ready."
] if probes["xcodebuild"]["available"] and not xcode_ready else [],
}
def main() -> int:
failures: list[str] = []
package = json.loads(read(APP / "package.json"))
manifest = json.loads(read(APP / "public" / "manifest.webmanifest"))
sw = read(APP / "public" / "sw.js")
html = read(APP / "index.html")
api_server = read(ROOT / "scripts" / "jyotish_api_server.py")
main_js = read(APP / "main.js")
click_smoke = read(ROOT / "tests" / "run_frontend_click_smoke.py")
scripts = package.get("scripts", {})
require("build" in scripts, "jyotish-app/package.json missing build script", failures)
require("preview" in scripts, "jyotish-app/package.json missing preview script", failures)
require(manifest.get("name") == "Jyotish Vedic Astrology", "manifest name mismatch", failures)
require(manifest.get("display") == "standalone", "manifest display must be standalone", failures)
require(manifest.get("scope") == "/", "manifest scope must be /", failures)
require(manifest.get("start_url") == "/", "manifest start_url must be /", failures)
require(bool(manifest.get("theme_color")), "manifest theme_color missing", failures)
require(any(icon.get("src") == "/pwa-icon.svg" for icon in manifest.get("icons", [])), "manifest icon missing", failures)
require("CACHE_NAME = 'jyotish-shell-v1'" in sw, "service worker cache name missing", failures)
require("url.pathname.startsWith('/api/')" in sw, "service worker must bypass API requests", failures)
require("caches.match('/index.html')" in sw, "service worker fallback missing", failures)
require('rel="manifest"' in html and "/manifest.webmanifest" in html, "index missing manifest link", failures)
require("/pwa-icon.svg" in html, "index missing app icon", failures)
require("JYOTISH_API_HOST', '127.0.0.1'" in api_server, "API host default must stay loopback", failures)
require("Trust Center" in main_js and "Local-first" in main_js, "Trust Center status missing", failures)
require("pwa-install" in main_js and "promptPWAInstall" in main_js, "PWA install action missing", failures)
require(bool(re.search(r"127\.0\.0\.1:5200", main_js)), "Trust Center must show loopback API boundary", failures)
require("tests/run_frontend_click_smoke.py" in read(ROOT / "scripts" / "run_quality_gate.py"), "quality gate must run browser click smoke", failures)
require("--mode" in click_smoke and "all" in click_smoke, "click smoke must support --mode all", failures)
require("offline_recovery_guidance_visible" in click_smoke, "click smoke must verify offline recovery guidance", failures)
require("manifest.webmanifest" in click_smoke and "serviceWorker" in click_smoke, "click smoke must verify PWA installed shell", failures)
if failures:
print(json.dumps({"valid": False, "failures": failures}, ensure_ascii=False, indent=2))
return 1
first_launch_checks = [
{
"path": "PWA installed shell",
"command": "python3 tests/run_frontend_click_smoke.py --mode all",
"expected": "manifest.webmanifest, serviceWorker, mobile shell, online workflow, and offline recovery guidance",
},
{
"path": "Pake first launch",
"command": "cd jyotish-app && npm run build && npm run preview -- --host 127.0.0.1 --port 4173",
"expected": "URL shell can open the built app; local API still needs python3 scripts/jyotish_api_server.py on 127.0.0.1:5200",
},
{
"path": "Tauri sidecar readiness",
"command": "python3 scripts/desktop_packaging_preflight.py",
"expected": "loopback API boundary, sidecar route, manifest, service worker, and Trust Center remain visible before scaffolding",
},
]
print(json.dumps({
"valid": True,
"packaging_paths": ["pwa", "pake-url-shell", "tauri-sidecar-spike"],
"app_dir": str(APP),
"api_default": "127.0.0.1:5200",
"first_launch_checks": first_launch_checks,
"toolchain_probe": toolchain_probe(),
}, ensure_ascii=False, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())
-27
View File
@@ -37,12 +37,7 @@ def _python_module_status(module_name: str) -> dict[str, Any]:
}
def _package_has_dependency(package_text: str, dependency: str) -> bool:
return f'"{dependency}"' in package_text or f"'{dependency}'" in package_text
def build_probe() -> dict[str, Any]:
package_json = _read_text("jyotish-app", "package.json")
product_gap = _read_text("docs", "research", "product_gap_matrix_2026_06_22.md")
open_source_scan = _read_text("docs", "research", "open_source_scan_2026_06_22.md")
@@ -50,12 +45,6 @@ def build_probe() -> dict[str, Any]:
swisseph_python_available = swisseph_python_module["available"] and "import swisseph as swe" in _read_text(
"scripts", "jyotish_api_server.py"
)
swisseph_wasm_files = [
"jyotish-app/lib/swisseph-wasm/swisseph.js",
"jyotish-app/public/swisseph/swisseph.js",
]
swisseph_wasm_available = any(_exists(*path.split("/")) for path in swisseph_wasm_files)
vedastro_local = _exists("references", "open_source_sources", "VedicAstro")
vedastro_scan = "VedAstro/VedAstro" in open_source_scan or "VedAstro/VedAstro" in product_gap
external_benchmark_scan = "naturalstupid/PyJHora" in open_source_scan or "PyJHora" in product_gap
@@ -72,21 +61,6 @@ def build_probe() -> dict[str, Any]:
],
"next_step": "keep as canonical longitude source until another backend passes parity cases",
},
"swisseph_wasm": {
"available": bool(swisseph_wasm_available),
"replacement_readiness": "fallback",
"license_posture": "browser fallback using Swiss Ephemeris WASM assets; same boundary as Swiss Ephemeris",
"evidence": [
path for path in swisseph_wasm_files if _exists(*path.split("/"))
]
+ [
{
"@swisseph/browser": _package_has_dependency(package_json, "@swisseph/browser"),
"swisseph-wasm": _package_has_dependency(package_json, "swisseph-wasm"),
}
],
"next_step": "keep for local-first browser degradation, not as a separate accuracy baseline",
},
"xalen_ephemeris": {
"available": False,
"replacement_readiness": "spike_only",
@@ -130,7 +104,6 @@ def build_probe() -> dict[str, Any]:
},
"replacement_readiness": {
"primary": ["swisseph_python"],
"fallback": ["swisseph_wasm"],
"spike_only": ["xalen_ephemeris"],
"service_adapter_candidate": ["vedastro"],
"benchmark_only": ["external_benchmark_benchmark"],
@@ -20,54 +20,7 @@ def _exists(*parts: str) -> bool:
return ROOT.joinpath(*parts).exists()
def _read(*parts: str) -> str:
path = ROOT.joinpath(*parts)
if not path.exists():
return ""
return path.read_text(encoding="utf-8", errors="ignore")
def _package_dependency(name: str) -> bool:
package = _read("jyotish-app", "package.json")
return f'"{name}"' in package or f"'{name}'" in package
def _package_license(*parts: str) -> str:
text = _read(*parts)
if not text:
return "not_found"
try:
data = json.loads(text)
except json.JSONDecodeError:
return "unreadable"
return str(data.get("license") or "unspecified")
def build_spike() -> Dict[str, Any]:
swisseph_wasm_assets = [
"jyotish-app/public/swisseph-wasm/wasm/swisseph.wasm",
"jyotish-app/public/swisseph/swisseph.wasm",
"jyotish-app/lib/swisseph-wasm/swisseph.js",
]
swisseph_wasm_candidate = {
"candidate_backend": "swisseph_wasm_candidate",
"candidate_adapter_spike": "asset_detected_no_runtime_switch",
"available": any(_exists(*path.split("/")) for path in swisseph_wasm_assets),
"evidence": [path for path in swisseph_wasm_assets if _exists(*path.split("/"))],
"dependencies": {
"@swisseph/browser": _package_dependency("@swisseph/browser"),
"swisseph-wasm": _package_dependency("swisseph-wasm"),
},
"package_license": {
"@swisseph/browser": _package_license("jyotish-app", "node_modules", "@swisseph", "browser", "package.json"),
"swisseph-wasm": _package_license("jyotish-app", "node_modules", "swisseph-wasm", "package.json"),
},
"license_gate": "Swiss Ephemeris WASM remains under Swiss Ephemeris licensing boundaries; verify commercial/GPL compatibility before distribution claims.",
"distribution_gate": "AGPL-3.0 and GPL-3.0-or-later packages must not be treated as low-risk proprietary desktop/PWA dependencies.",
"runtime_setting_exposure": "blocked_until_parity_gate_required",
"parity_gate_required": "Must emit EphemerisAdapterContract rows and pass swisseph_python longitude_delta_arcsec thresholds.",
}
xalen_local_paths = [
"references/open_source_sources/xalen-ephemeris",
"references/open_source_sources/xalen",
@@ -102,14 +55,11 @@ def build_spike() -> Dict[str, Any]:
"candidate_adapter_spike": True,
"runtime_setting_exposure": "do_not_expose_non_swisseph_backend_yet",
"license_gate": {
"swisseph_wasm_candidate": swisseph_wasm_candidate["license_gate"],
"xalen_ephemeris_candidate": xalen_ephemeris_candidate["license_gate"],
"vedastro_service_adapter_candidate": vedastro_service_adapter_candidate["license_gate"],
},
"package_license": swisseph_wasm_candidate["package_license"],
"parity_gate_required": "Run scripts/ephemeris_adapter_contract.py with real candidate rows before settings exposure.",
"candidate_backends": {
"swisseph_wasm_candidate": swisseph_wasm_candidate,
"xalen_ephemeris_candidate": xalen_ephemeris_candidate,
"vedastro_service_adapter_candidate": vedastro_service_adapter_candidate,
},
@@ -18,7 +18,6 @@ from scripts.strict_evidence_service import existing_interpretation_source_pack
REQUIRED_LAYERS = [
"primary_truth",
"frontend_interpretation",
"qa_governance",
"reader_validation",
"yoga_rules",
@@ -29,7 +28,7 @@ REQUIRED_LAYERS = [
SCAN_ROOTS = [
"references",
"docs",
"jyotish-app",
"frontend",
"assets",
"SKILL.md",
"AGENTS.md",
@@ -271,7 +270,7 @@ def _classify_candidate(path: str, runtime_source_refs: set[str], layer_refs: se
"promotion_status": "benchmark_evidence_only",
"reason": "Benchmark or evidence report; use for validation boundaries, not direct rules.",
}
if path.startswith("jyotish-app/"):
if path.startswith("frontend/"):
return {
"classification": "frontend_surface",
"priority": "priority_3",
+39 -53
View File
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
"""
印度占星 API 服务器 v1.0
jyotish-app 前端提供 v6.9.14 引擎的精算能力
Next.js 产品前端提供 v6.9.14 引擎的精算能力
启动: python3 scripts/jyotish_api_server.py --port 5200
"""
@@ -1304,8 +1304,8 @@ DEFAULT_ALLOWED_ORIGINS = {
'http://127.0.0.1:3456',
'http://localhost:3457',
'http://127.0.0.1:3457',
'http://localhost:5173',
'http://127.0.0.1:5173',
'http://localhost:3000',
'http://127.0.0.1:3000',
}
DEFAULT_ALLOWED_HOSTS = {'localhost', '127.0.0.1', '::1'}
MAX_REQUEST_BYTES = 2 * 1024 * 1024
@@ -7582,7 +7582,7 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
techniques = registry.get('techniques', {})
engine_commands = self._scan_engine_commands()
api_endpoints = self._scan_api_endpoints()
app_tabs = self._scan_app_tabs()
app_routes = self._scan_app_routes()
local_sources = self._scan_local_open_source_sources()
command_set = set(engine_commands)
api_command_map = API_COMMAND_MAP
@@ -7591,7 +7591,7 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
for command, endpoint in api_command_map.items()
if endpoint in api_endpoints or command in command_set
)
app_visible_topics = self._app_visible_topics(app_tabs)
app_visible_topics = self._app_visible_topics()
registry_commands = sorted({
command
for technique in techniques.values()
@@ -7652,8 +7652,8 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
'api_backed_commands': api_backed_commands,
'engine_not_api': engine_not_api,
'registry_only_commands': registry_only_commands,
'app_tab_count': len(app_tabs),
'app_tabs': app_tabs,
'app_route_count': len(app_routes),
'app_routes': app_routes,
'app_visible_topics': app_visible_topics,
},
'local_open_source': {
@@ -8111,33 +8111,40 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
return []
return sorted(set(re.findall(r"path == ['\"](/api/[^'\"]+)['\"]", text)))
def _scan_app_tabs(self):
path = os.path.join(REPO_ROOT, 'jyotish-app', 'index.html')
try:
with open(path, 'r', encoding='utf-8') as f:
text = f.read()
except OSError:
def _scan_app_routes(self):
root = os.path.join(REPO_ROOT, 'frontend', 'src', 'app')
if not os.path.isdir(root):
return []
return sorted(set(re.findall(r'data-tab="([^"]+)"', text)))
routes = []
for dirpath, _, filenames in os.walk(root):
if not {'page.tsx', 'page.ts', 'page.jsx', 'page.js'}.intersection(filenames):
continue
relative = os.path.relpath(dirpath, root)
routes.append('home' if relative == '.' else relative.replace(os.sep, '/'))
return sorted(set(routes))
def _scan_app_source_text(self):
root = os.path.join(REPO_ROOT, 'jyotish-app')
if not os.path.isdir(root):
return ''
roots = [
os.path.join(REPO_ROOT, 'frontend', 'src', 'app'),
os.path.join(REPO_ROOT, 'frontend', 'src', 'components'),
]
chunks = []
for dirpath, dirnames, filenames in os.walk(root):
dirnames[:] = [
d for d in dirnames
if d not in {'node_modules', 'dist', '.vite', '.git'}
]
for filename in filenames:
if not filename.endswith(('.js', '.html', '.css')):
continue
try:
with open(os.path.join(dirpath, filename), 'r', encoding='utf-8', errors='ignore') as f:
chunks.append(f.read(40000))
except OSError:
continue
for root in roots:
if not os.path.isdir(root):
continue
for dirpath, dirnames, filenames in os.walk(root):
dirnames[:] = [
d for d in dirnames
if d not in {'api', 'node_modules', '.next', '.git'}
]
for filename in filenames:
if not filename.endswith(('.js', '.jsx', '.ts', '.tsx', '.html', '.css')):
continue
try:
with open(os.path.join(dirpath, filename), 'r', encoding='utf-8', errors='ignore') as f:
chunks.append(f.read(40000))
except OSError:
continue
return '\n'.join(chunks).lower()
def _scan_local_open_source_sources(self):
@@ -8258,29 +8265,8 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
found.append(module)
return found
def _app_visible_topics(self, tabs):
mapping = {
'chart': 'D1/Rashi',
'complete': 'Full Reading',
'karaka': 'Jaimini Karaka',
'houses': 'Bhava',
'aspects': 'Aspects',
'yogas': 'Yoga',
'vargas': 'Varga',
'ashtakavarga': 'Ashtakavarga',
'shadbala': 'Shadbala',
'dasha': 'Dasha',
'transit': 'Transit',
'deep': 'PACDARES/Argala',
'extended': 'Bhava Bala/Vimsopaka',
'remedies': 'Remedies',
'synastry': 'Synastry',
'prashna': 'Prashna',
'kp': 'KP',
'verify': 'Verification',
'transit-compare': 'Transit Compare',
}
topics = [mapping[t] for t in tabs if t in mapping]
def _app_visible_topics(self):
topics = []
source_text = self._scan_app_source_text()
source_markers = {
'Muhurta': ['computemuhurta', 'muhurta'],
-3
View File
@@ -1835,9 +1835,6 @@ def _build_ai_prompt_pack(report):
'references/raman-house-judgment-methodology.md',
'references/mandatory-verification-gate-protocol.md',
'references/real-reading-quality-checklist.md',
'jyotish-app/planet-house-details-a.js',
'jyotish-app/planet-house-details-b.js',
'jyotish-app/planet-house-details-c.js',
],
'retrieval_tags': [
'no_single_factor_conclusion',
+7 -51
View File
@@ -18,7 +18,7 @@ sys.path.insert(0, str(ROOT / "scripts"))
from local_env import load_local_env # noqa: E402
load_local_env(ROOT)
APP = ROOT / "jyotish-app"
APP = ROOT / "frontend"
PYTHON = sys.executable
COMPILE_DIRS = [
@@ -37,14 +37,11 @@ EXTRA_COMPILE_TARGETS = [
ROOT / "scripts" / "oracle_collection_queue.py",
ROOT / "scripts" / "oracle_evidence_validator.py",
ROOT / "scripts" / "sync_final_evidence_packet_status.py",
ROOT / "scripts" / "deployment_preflight.py",
ROOT / "tests" / "run_golden_cases.py",
ROOT / "tests" / "run_real_case_revalidation.py",
ROOT / "tests" / "run_frontend_runtime_smoke.py",
]
CORE_PYTEST_TARGETS = [
"tests/test_frontend_productization.py",
"tests/test_cli_smoke.py",
"tests/test_api_server_security.py",
"tests/test_jaimini.py",
@@ -63,7 +60,6 @@ RUNTIME_TRUTH_PYTEST_TARGETS = [
"tests/test_interpretation_source_inventory_gate.py::test_quality_gate_runs_interpretation_source_inventory_gate",
"tests/test_interpretation_source_runtime_coverage.py",
"tests/test_final_jhora_evidence_packet_acceptance.py",
"tests/test_frontend_productization.py::test_result_page_surfaces_workflow_summary_and_provenance_detail",
]
RELEASE_CRITICAL_UNTRACKED_PATHS = [
@@ -75,19 +71,10 @@ RELEASE_CRITICAL_UNTRACKED_PATHS = [
"docs/research/product_gap_matrix_2026_06_22.md",
"docs/research/whole_machine_git_audit_2026_06_23.md",
"findings.md",
"jyotish-app/import-chart.js",
"jyotish-app/mevg-audit.js",
"jyotish-app/public/manifest.webmanifest",
"jyotish-app/public/pwa-icon.svg",
"jyotish-app/public/sw.js",
"jyotish-app/security.js",
"jyotish-app/skill-map.js",
"progress.md",
"references/oracle/dasha_shadbala_oracle_cases.json",
"scripts/audit_fragments.py",
"scripts/deep_varga_avastha.py",
"scripts/deployment_preflight.py",
"scripts/desktop_packaging_preflight.py",
"scripts/dasha_reference_audit.py",
"scripts/ephemeris_adapter_contract.py",
"scripts/ephemeris_backend_probe.py",
@@ -96,12 +83,9 @@ RELEASE_CRITICAL_UNTRACKED_PATHS = [
"scripts/oracle_collection_queue.py",
"scripts/oracle_evidence_validator.py",
"task_plan.md",
"tests/run_frontend_click_smoke.py",
"tests/run_frontend_runtime_smoke.py",
"tests/test_api_server_security.py",
"tests/test_dasha_reference_audit.py",
"tests/test_deep_varga_avastha.py",
"tests/test_frontend_productization.py",
"tests/test_oracle_boundary_audit.py",
"tests/test_oracle_collection_queue.py",
"tests/test_oracle_evidence_validator.py",
@@ -112,8 +96,6 @@ QUALITY_GATE_PROFILES = {
"skip_slow": True,
"skip_yoga_logic": True,
"skip_frontend_runtime": False,
"skip_frontend_click": True,
"frontend_click_mode": "core",
"check_release_hygiene": False,
"skip_real_cases": True,
"skip_dasha_audit": True,
@@ -125,8 +107,6 @@ QUALITY_GATE_PROFILES = {
"skip_slow": True,
"skip_yoga_logic": True,
"skip_frontend_runtime": False,
"skip_frontend_click": False,
"frontend_click_mode": "all",
"check_release_hygiene": False,
"skip_real_cases": True,
"skip_dasha_audit": True,
@@ -138,8 +118,6 @@ QUALITY_GATE_PROFILES = {
"skip_slow": False,
"skip_yoga_logic": False,
"skip_frontend_runtime": False,
"skip_frontend_click": False,
"frontend_click_mode": "all",
"check_release_hygiene": True,
"skip_real_cases": False,
"skip_dasha_audit": False,
@@ -151,8 +129,6 @@ QUALITY_GATE_PROFILES = {
"skip_slow": True,
"skip_yoga_logic": False,
"skip_frontend_runtime": True,
"skip_frontend_click": True,
"frontend_click_mode": "core",
"check_release_hygiene": False,
"skip_real_cases": False,
"skip_dasha_audit": False,
@@ -164,8 +140,6 @@ QUALITY_GATE_PROFILES = {
"skip_slow": True,
"skip_yoga_logic": True,
"skip_frontend_runtime": True,
"skip_frontend_click": True,
"frontend_click_mode": "core",
"check_release_hygiene": False,
"skip_real_cases": True,
"skip_dasha_audit": True,
@@ -177,8 +151,6 @@ QUALITY_GATE_PROFILES = {
"skip_slow": True,
"skip_yoga_logic": True,
"skip_frontend_runtime": True,
"skip_frontend_click": True,
"frontend_click_mode": "core",
"check_release_hygiene": False,
"skip_real_cases": True,
"skip_dasha_audit": True,
@@ -301,10 +273,9 @@ def format_failure_summary(
lines.extend([
"普通用户启动路径:",
"1. 本地 API 服务:.venv/bin/python scripts/jyotish_api_server.py --host 127.0.0.1 --port 5200",
"2. 网页服务:cd jyotish-app && npm run dev -- --host 127.0.0.1 --port 5173",
"3. Open http://127.0.0.1:5173, then open Trust Center and run the health check.",
"4. PWA 安装壳只包装网页服务,本地 API 服务仍需单独启动。",
"Next action: Run the focused command above, add --keep-logs for browser click smoke, then compare the app state with the startup path above.",
"2. 网页服务:npm run dev --prefix frontend",
"3. Open http://127.0.0.1:3000 and verify /api/health.",
"Next action: Run the focused command above, then rerun the affected Python or Next.js check.",
"",
])
return "\n".join(lines)
@@ -469,7 +440,6 @@ def run_profile(args: argparse.Namespace) -> dict:
"skip_slow",
"skip_yoga_logic",
"skip_frontend_runtime",
"skip_frontend_click",
"skip_real_cases",
"skip_dasha_audit",
"skip_oracle_audit",
@@ -478,8 +448,6 @@ def run_profile(args: argparse.Namespace) -> dict:
]:
if getattr(args, key):
profile[key] = True
if args.frontend_click_mode:
profile["frontend_click_mode"] = args.frontend_click_mode
return profile
@@ -488,15 +456,12 @@ def main() -> int:
parser.add_argument("--profile", choices=["quick", "browser", "release", "accuracy", "vedastro-live", "runtime-truth"], default="browser", help="Quality gate profile: quick, browser, release, accuracy, vedastro-live, or runtime-truth")
parser.add_argument("--skip-slow", action="store_true", help="Skip slow golden-case regressions")
parser.add_argument("--skip-yoga-logic", action="store_true", help="Skip Yoga logic comparison report refresh")
parser.add_argument("--skip-frontend-runtime", action="store_true", help="Skip frontend build and runtime smoke")
parser.add_argument("--skip-frontend-click", action="store_true", help="Skip browser click smoke")
parser.add_argument("--skip-frontend-runtime", action="store_true", help="Skip Next.js tests, lint, and production build")
parser.add_argument("--skip-real-cases", action="store_true", help="Skip public real-person chart revalidation")
parser.add_argument("--skip-dasha-audit", action="store_true", help="Skip Dasha reference-drift audit")
parser.add_argument("--skip-oracle-audit", action="store_true", help="Skip combined Dasha/Shadbala external oracle boundary audit")
parser.add_argument("--skip-local-accuracy-report", action="store_true", help="Skip consolidated local accuracy report")
parser.add_argument("--skip-vedastro-live", action="store_true", help="Skip optional VedAstro live endpoint smoke")
parser.add_argument("--frontend-click-mode", choices=["core", "mobile", "offline", "pdf", "workspace", "mobile-trust", "import-files", "all"], default=None, help="Browser click smoke mode for browser/release profiles")
parser.add_argument("--frontend-click-timeout", type=int, default=240, help="Timeout seconds for browser click smoke")
parser.add_argument("--all-tests", action="store_true", help="Run every pytest file, including optional-dependency suites")
parser.add_argument("--require-external-parity", action="store_true", help="Fail the release gate unless the three-engine raw parity manifest passes.")
args = parser.parse_args()
@@ -528,7 +493,6 @@ def main() -> int:
run([PYTHON, "scripts/audit_fragments.py", "--strict"])
run([PYTHON, "scripts/interpretation_source_inventory_gate.py"])
run([PYTHON, "scripts/character_level_inventory_manifest.py", "--scope", "project", "--no-write", "--summary-only"])
run([PYTHON, "scripts/deployment_preflight.py"])
if profile["check_release_hygiene"]:
release_hygiene_check(require_external_parity=args.require_external_parity)
run([PYTHON, "scripts/validate_bphs_invariants.py"])
@@ -540,17 +504,9 @@ def main() -> int:
pytest_targets = CORE_PYTEST_TARGETS
run([PYTHON, "-m", "pytest", *pytest_targets])
if not profile["skip_frontend_runtime"]:
run(["npm", "test"], optional=False, cwd=APP)
run(["npm", "run", "lint"], optional=False, cwd=APP)
run(["npm", "run", "build"], optional=False, cwd=APP)
run([PYTHON, "tests/run_frontend_runtime_smoke.py", "--start-if-needed"])
if not profile["skip_frontend_click"]:
run([
PYTHON,
"tests/run_frontend_click_smoke.py",
"--mode",
profile["frontend_click_mode"],
"--timeout",
str(args.frontend_click_timeout),
])
if not profile["skip_slow"]:
run([PYTHON, "tests/run_golden_cases.py", "--python", PYTHON])
if not profile["skip_real_cases"]:
@@ -17,7 +17,6 @@ def build_audit(root: Path) -> dict:
full_reading = root / "scripts/full_reading.py"
api_server = root / "scripts/jyotish_api_server.py"
deep = root / "scripts/deep_varga_avastha.py"
skill_map = root / "jyotish-app/skill-map.js"
tests = root / "tests/test_cli_smoke.py"
deep_tests = root / "tests/test_deep_varga_avastha.py"
@@ -43,11 +42,10 @@ def build_audit(root: Path) -> dict:
"main_artifacts": [
"scripts/deep_varga_avastha.py",
"scripts/jyotish_api_server.py",
"jyotish-app/skill-map.js",
"tests/test_deep_varga_avastha.py",
],
"historical_artifacts": ["skills/jyotish-engine-modules/scripts/avastha_calculator.py"],
"entrypoints": ["/api/deep_varga_avastha", "jyotish-app skill-map deepVargaAvastha"],
"entrypoints": ["/api/deep_varga_avastha"],
"reuse_decision": "do_not_duplicate_runtime",
"next_action": "add_display_contract_and_source_oracle_packet",
"claim_boundary": "Avastha is endpoint-visible, but formula variants and interpretive claim level still need source/oracle packet.",
+2 -2
View File
@@ -170,7 +170,7 @@ VEDASTRO_CAPABILITY_SEEDS: list[dict[str, Any]] = [
"vedastro_capability": "Report Rendering",
"category": "presentation",
"domains": ["report", "image"],
"local_assets": ["report_artifact API", "report_builder.py", "chart_renderer.py", "jyotish-app export"],
"local_assets": ["report_artifact API", "report_builder.py", "chart_renderer.py"],
"can_call_vedastro": False,
"recommended_path": "new_local_impl",
"fastest_path_lane": "local_native_preferred",
@@ -218,7 +218,7 @@ VEDASTRO_CAPABILITY_SEEDS: list[dict[str, Any]] = [
"vedastro_capability": "Birth Time ML / Rectification Assistant",
"category": "birth_time_rectification",
"domains": ["birth"],
"local_assets": ["birth_time_rectifier.py", "rectification_gate", "jyotish-app rectification"],
"local_assets": ["birth_time_rectifier.py", "rectification_gate"],
"can_call_vedastro": True,
"recommended_path": "hybrid_local_plus_vedastro",
"fastest_path_lane": "rest_adapter",