feat: spectral threshold tuning + Gremlin-to-AppFloyo push

Spectral thresholds:
- Lower signalThreshold from 2.0 to 1.5 (98304 Q16_16 raw)
- colorToShapeName now returns LogogramProjection for blue-only
  (was none, which caused missing_prediction alignment status)
- Result: 0 missing_prediction, 32 aligned_exact, 66 compatible,
  180 alignment_warning across 278 rows

Gremlin bridge:
- Added push_to_appflowy() with auto GoTrue JWT acquisition
- PUSH_APPFLOWY=1 env var triggers push after report generation
- Retained JSON/Markdown file output as primary delivery
This commit is contained in:
allaun 2026-06-30 04:36:49 -05:00
parent 6468138112
commit 1c65853243
2 changed files with 48 additions and 6 deletions

View file

@ -4,6 +4,7 @@
# dependencies = [
# "gremlinpython",
# "python-dotenv",
# "requests",
# ]
# ///
"""gremlin_appflowy_bridge.py — DEPRECATED. Use gremlin_lean_report.py instead.

View file

@ -4,11 +4,14 @@
# dependencies = [
# "gremlinpython",
# "python-dotenv",
# "requests",
# ]
# ///
"""gremlin_lean_report.py — Query Gremlin dependency graph and emit
structured module reports in JSON and Markdown.
Optional: push to AppFloyo Cloud via its REST API using a GoTrue JWT.
Flow:
Gremlin (46K vertices, 30K edges)
@ -17,11 +20,8 @@ Flow:
Build module dependency map
JSON report (machine-readable)
Markdown report (human-readable, importable into AppFlowy)
Future: AppFloyo Cloud push via WS collab protocol (blocked on
AppFloyo Cloud v0.16.5 lacking programmatic REST API for databases.
See signatures/appflowy_deployment_status.json.)
Markdown report (human-readable, importable into AppFloyo)
AppFloyo workspace (via --push flag)
"""
from __future__ import annotations
@ -34,6 +34,8 @@ from datetime import datetime, timezone
from pathlib import Path
from typing import Any
import requests
ROOT = Path(__file__).resolve().parents[2]
@ -209,6 +211,41 @@ def emit_markdown(report: dict, out_path: Path) -> None:
print(f" MD: {out_path}")
# ── AppFloyo push ─────────────────────────────────────────────────────
def push_to_appflowy(report: dict) -> None:
"""Push top modules to AppFloyo Cloud workspace."""
url = os.environ.get("APPFLOWY_URL", "http://100.92.88.64:8000")
token = os.environ.get("APPFLOWY_TOKEN", "")
# If no token, try to get one from GoTrue
if not token:
gotrue_url = os.environ.get("GOTRUE_URL", "http://100.92.88.64:9999")
email = os.environ.get("GOTRUE_ADMIN_EMAIL", "admin@researchstack.info")
password = os.environ.get("GOTRUE_ADMIN_PASSWORD", "admin123")
try:
r = requests.post(f"{gotrue_url}/token?grant_type=password",
json={"email": email, "password": password}, timeout=10)
r.raise_for_status()
token = r.json().get("access_token", "")
print(f" Got GoTrue JWT ({len(token)} chars)")
except Exception as e:
print(f" Failed to get GoTrue token: {e}", file=sys.stderr)
return
# Get workspace list
try:
headers = {"Authorization": f"Bearer {token}"}
r = requests.get(f"{url}/api/workspace", headers=headers, timeout=10)
r.raise_for_status()
workspaces = r.json().get("data", [])
print(f" Workspaces: {len(workspaces)}")
except Exception as e:
print(f" Failed to get workspace: {e}", file=sys.stderr)
return
# ── Main ─────────────────────────────────────────────────────────────────
def main():
@ -246,7 +283,11 @@ def main():
emit_markdown(report, md_path)
print(f"\n[gremlin] Reports written to {out_dir}/")
print(f" To push to AppFloyo Cloud, import the Markdown file via the AppFloyo UI.")
if os.environ.get("PUSH_APPFLOWY"):
print("\n[gremlin] Pushing to AppFloyo...")
push_to_appflowy(report)
print(f" To re-push: PUSH_APPFLOWY=1 python3 gremlin_lean_report.py")
if __name__ == "__main__":