On this page

DISCOVERY_REPORT.md

Discovery snapshot

Historical snapshot. Generated 14 September 2026. Routes have changed since. Kept here because you asked for the whole record.

Aegis-Terminal — Discovery Report

_Generated 2026-09-14 14:43 PDT. Read-only — no writes, no server, no network calls made._

1. Routes

POST /tutorial/generate

./tutorials.py:747 (handler: _generate)

    def _generate(req: EvolveRequest):
        topic = req.topic.strip()
        if not topic:
            return {"ok": False, "error": "topic required"}
        sources = _gather_sources(topic)
        if not sources:
            return {"ok": False, "error": "no sources found"}
        result = generate_natural_tutorial(topic, sources)
        if result.get("ok"):
            try:
                _save_tutorial(topic, result["raw"], notes="initial")
            except Exception as e:
                result["store_warning"] = str(e)
        return result

    @app.post("/tutorial/evolve")
    def _evolve(req: EvolveRequest):
        import teach
        topic = req.topic.strip()
        if not topic:
            return {"ok": False, "error": "topic required"}
# ... (135 more lines truncated)

POST /tutorial/evolve

./tutorials.py:763 (handler: _evolve)

    def _evolve(req: EvolveRequest):
        import teach
        topic = req.topic.strip()
        if not topic:
            return {"ok": False, "error": "topic required"}
        import tutorials_struct
        is_prog = tutorials_struct._is_prog(topic)

        # 1. Fetch NEXT batch using offset
        expanded = None
        offset = tutorials_struct.get_offset(topic)
        print("[evolve] topic=" + topic + " offset=" + str(offset))
        try:
            expanded = tutorials_struct.expand_structural(topic, offset=offset)
        except Exception as _e:
            print("[tutorial] expand failed: " + str(_e))

        if expanded:
            # 2. Merge with previous steps (dedup by title)
            prev_steps = []
            prev_parsed = {}
# ... (119 more lines truncated)

POST /tutorial/store

./tutorials.py:868 (handler: _store)

    def _store(req: StoreRequest):
        try:
            doc_id = _save_tutorial(req.topic, req.raw, notes=req.notes)
            return {"ok": True, "doc_id": doc_id}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    @app.get("/tutorial/history/{topic}")
    def _history(topic: str):
        import teach, duckdb, config
        doc_id = teach._topic_key(topic)
        try:
            con = duckdb.connect(config.DUCKDB_PATH)
            rows = con.execute(
                "SELECT version, created_at, length(tutorial) "
                "FROM tutorial_versions WHERE doc_id=? "
                "ORDER BY version DESC", [doc_id]).fetchall()
            con.close()
            return {"ok": True, "versions": [
                {"version": r[0], "created_at": r[1], "chars": r[2]}
                for r in rows]}
# ... (14 more lines truncated)

GET /tutorial/history/{topic}

./tutorials.py:876 (handler: _history)

    def _history(topic: str):
        import teach, duckdb, config
        doc_id = teach._topic_key(topic)
        try:
            con = duckdb.connect(config.DUCKDB_PATH)
            rows = con.execute(
                "SELECT version, created_at, length(tutorial) "
                "FROM tutorial_versions WHERE doc_id=? "
                "ORDER BY version DESC", [doc_id]).fetchall()
            con.close()
            return {"ok": True, "versions": [
                {"version": r[0], "created_at": r[1], "chars": r[2]}
                for r in rows]}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    @app.get("/tutorial/latest/{topic}")
    def _latest(topic: str):
        import teach
        prev = teach._latest_version(topic)
        if not prev:
# ... (6 more lines truncated)

GET /tutorial/latest/{topic}

./tutorials.py:893 (handler: _latest)

    def _latest(topic: str):
        import teach
        prev = teach._latest_version(topic)
        if not prev:
            return {"ok": False, "error": "no stored tutorial"}
        parsed = parse_tutorial(prev["tutorial"])
        parsed["ok"] = True
        parsed["version"] = prev["version"]
        parsed["created_at"] = prev["created_at"]
        return parsed

GET /

./main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (1091 more lines truncated)

POST /ingest

./main.py:1614 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./main.py:1629 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./main.py:1637 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./main.py:1667 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./main.py:1708 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./main.py:1717 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./main.py:1722 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./main.py:1729 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./main.py:1735 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./main.py:1745 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./main.py:1774 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./main.py:1792 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./main.py:1800 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./main.py:1813 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./main.py:1833 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./main.py:1852 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./main.py:1858 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./main.py:1863 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./main.py:1869 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./main.py:1875 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./main.py:1883 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./main.py:1923 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./main.py:1930 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./main.py:1935 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./main.py:1940 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./main.py:1946 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./main.py:1975 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:387 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:450 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:473 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # AEGIS-FIX: disambiguation gate.
    # Runs before teach/math/units so ambiguous definition queries are
    # intercepted before any heavy pipeline. detect_ambiguity() only
    # fires on definition-shaped prompts (subject extraction rejects
    # everything else), so this is safe for all other query types.
    if getattr(config, "ENABLE_DISAMBIGUATION", False):
        try:
            import disambiguate as _dis
            import session_store as _sess
            from web_ingest import (
                fetch_wikipedia_summary as _wk_sum,
                fetch_disambiguation_candidates as _wk_cands,
            )

# ... (830 more lines truncated)

POST /ingest

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1325 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1340 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1348 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1378 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1419 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1428 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1433 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1440 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1446 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1456 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1485 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1503 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1511 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1517 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1523 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1531 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1571 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1578 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1583 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1588 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1594 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1623 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (575 more lines truncated)

POST /ingest

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1066 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1081 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1089 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1119 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1160 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1169 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1174 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1181 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1187 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1197 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1226 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1244 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1252 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1258 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1264 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1272 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1312 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1319 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1324 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1329 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1335 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1364 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:387 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:450 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:473 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: terminal sense resolution in query.
    # When req.sense is set, the user has explicitly picked a sense.
    # We resolve it directly from the wiktionary doc and return
    # immediately — bypassing the cache, the disambiguation gate, and
    # the entire pipeline. Nothing downstream can overwrite the answer.
    # AEGIS-FIX: multi-token subject terminal.
    # Also fires when the classifier extracts a multi-token subject
    # (e.g. "Apple Inc", "Barack Obama") even without an explicit sense
    # field. Multi-token subjects are already specific — the user
    # disambiguated by typing them — so if we have a wiktionary doc for
    # exactly that subject, return it directly.
    _terminal_subject = None
    if getattr(req, "sense", None):
        _terminal_subject = req.sense.replace("_", " ").title()
    else:
        try:
            import definition_path as _dp_probe
            _probe = _dp_probe.classify(req.prompt)
            _psubj = _probe.get("subject") or ""
            if _probe.get("is_definition") and _psubj and " " in _psubj:
# ... (665 more lines truncated)

POST /ingest

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1160 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1175 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1183 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1213 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1254 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1263 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1268 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1275 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1281 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1291 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1320 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1338 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1346 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1352 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1358 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1366 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1406 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1413 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1418 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1423 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1429 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1458 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:393 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:456 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:479 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (840 more lines truncated)

POST /ingest

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1342 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1357 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1365 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1395 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1436 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1445 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1450 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1457 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1463 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1473 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1502 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1520 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1528 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1541 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1561 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1580 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1586 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1591 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1597 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1603 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1611 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1651 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1658 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1663 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1668 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1674 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1703 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (894 more lines truncated)

POST /ingest

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1417 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1432 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1440 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1470 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1511 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1520 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1525 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1532 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1538 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1548 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1577 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1595 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1603 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1616 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1636 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1655 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1661 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1666 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1672 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1678 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1686 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1726 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1733 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1738 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1743 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1749 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1778 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:389 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:452 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:475 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: terminal sense resolution in query.
    # When req.sense is set, the user has explicitly picked a sense.
    # We resolve it directly from the wiktionary doc and return
    # immediately — bypassing the cache, the disambiguation gate, and
    # the entire pipeline. Nothing downstream can overwrite the answer.
    # AEGIS-FIX: multi-token subject terminal.
    # Also fires when the classifier extracts a multi-token subject
    # (e.g. "Apple Inc", "Barack Obama") even without an explicit sense
    # field. Multi-token subjects are already specific — the user
    # disambiguated by typing them — so if we have a wiktionary doc for
    # exactly that subject, return it directly.
    _terminal_subject = None
    if getattr(req, "sense", None):
        _terminal_subject = req.sense.replace("_", " ").title()
    else:
        try:
            import definition_path as _dp_probe
            _probe = _dp_probe.classify(req.prompt)
            _psubj = _probe.get("subject") or ""
            if _probe.get("is_definition") and _psubj and " " in _psubj:
# ... (729 more lines truncated)

POST /ingest

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1227 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1242 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1250 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1280 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1321 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1330 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1335 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1342 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1348 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1358 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1387 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1405 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1413 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1426 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1446 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1465 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1471 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1476 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1482 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1488 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1496 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1536 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1543 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1548 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1553 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1559 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1588 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/20260912-210258/main.py:305 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(f.read())


# ---- Fresh-info intent detection ----
_CURRENT_INTENT_WORDS = {
    "price", "prices", "quote", "quotes", "rate", "rates",
    "spot", "level", "levels", "value", "values", "yield", "yields",
    "worth", "cost", "going", "today", "tonight", "tomorrow",
# ... (6 more lines truncated)

GET /health

./.aegis-doctor/backups/20260912-210258/main.py:350 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/20260912-210258/main.py:373 (handler: query)

def query(req: QueryRequest) -> dict:
    _unit_result = None
    try:
        session_log.log("query", f"prompt={req.prompt!r}")
    except Exception:
        pass
    try:
        _unit_result = units.try_compute(req.prompt)
        if _unit_result:
            print(f"[Aegis] Units: {_unit_result['answer']}")
    except Exception as _exc:
        print(f"[Aegis] Units error: {_exc}")

    # Stock price lookup — runs before the main pipeline
    _stock_result = None
    if not _unit_result:
        try:
            _stock_result = stock.try_compute(req.prompt)
            if _stock_result:
                print(f"[Aegis] Stock: {_stock_result['answer']}")
        except Exception as _exc:
# ... (391 more lines truncated)

POST /ingest

./.aegis-doctor/backups/20260912-210258/main.py:786 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/20260912-210258/main.py:801 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/20260912-210258/main.py:809 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/20260912-210258/main.py:839 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/20260912-210258/main.py:880 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/20260912-210258/main.py:889 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/20260912-210258/main.py:894 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/20260912-210258/main.py:901 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/20260912-210258/main.py:907 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/20260912-210258/main.py:917 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/20260912-210258/main.py:946 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/20260912-210258/main.py:964 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/20260912-210258/main.py:972 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/20260912-210258/main.py:978 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/20260912-210258/main.py:984 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/20260912-210258/main.py:992 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/20260912-210258/main.py:1032 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript")

GET /boot/status

./.aegis-doctor/backups/20260912-210258/main.py:1039 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/20260912-210258/main.py:1044 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/20260912-210258/main.py:1049 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/20260912-210258/main.py:1055 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/20260912-210258/main.py:1084 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (39 more lines truncated)

GET /

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:311 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(f.read())


# ---- Fresh-info intent detection ----
_CURRENT_INTENT_WORDS = {
    "price", "prices", "quote", "quotes", "rate", "rates",
    "spot", "level", "levels", "value", "values", "yield", "yields",
    "worth", "cost", "going", "today", "tonight", "tomorrow",
# ... (6 more lines truncated)

GET /health

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:356 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:379 (handler: query)

def query(req: QueryRequest) -> dict:
    _unit_result = None
    try:
        session_log.log("query", f"prompt={req.prompt!r}")
    except Exception:
        pass
    try:
        _unit_result = units.try_compute(req.prompt)
        if _unit_result:
            print(f"[Aegis] Units: {_unit_result['answer']}")
    except Exception as _exc:
        print(f"[Aegis] Units error: {_exc}")

    # Stock price lookup — runs before the main pipeline
    _stock_result = None
    if not _unit_result:
        try:
            _stock_result = stock.try_compute(req.prompt)
            if _stock_result:
                print(f"[Aegis] Stock: {_stock_result['answer']}")
        except Exception as _exc:
# ... (385 more lines truncated)

POST /ingest

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:786 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:801 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:809 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:839 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:880 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:889 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:894 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:901 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:907 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:917 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:946 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:964 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:972 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:978 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:984 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:992 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:1032 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript")

GET /boot/status

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:1039 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:1044 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:1049 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:1055 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:1084 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (39 more lines truncated)

GET /

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (585 more lines truncated)

POST /ingest

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1076 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1091 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1099 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1129 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1170 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1179 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1184 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1191 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1197 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1207 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1236 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1254 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1262 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1268 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1274 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1282 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1322 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1329 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1334 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1339 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1345 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1374 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (660 more lines truncated)

POST /ingest

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1153 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1168 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1176 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1206 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1247 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1256 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1261 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1268 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1274 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1284 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1313 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1331 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1339 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1345 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1351 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1359 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1399 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1406 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1411 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1416 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1422 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1451 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (1008 more lines truncated)

POST /ingest

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1531 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1546 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1554 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1584 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1625 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1634 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1639 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1646 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1652 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1662 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1691 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1709 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1717 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1730 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1750 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1769 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1775 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1780 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1786 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1792 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1800 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1840 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1847 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1852 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1857 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1863 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1892 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/all-three-20260913-210154/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/all-three-20260913-210154/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/all-three-20260913-210154/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (907 more lines truncated)

POST /ingest

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1430 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1445 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1453 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1483 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1524 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1533 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1538 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1545 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1551 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1561 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1590 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1608 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1616 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1629 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1649 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1668 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1674 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1679 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1685 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1691 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1699 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1739 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1746 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1751 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1756 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1762 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/all-three-20260913-210154/main.py:1791 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (484 more lines truncated)

POST /ingest

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:975 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:990 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:998 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1028 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1069 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1078 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1083 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1090 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1096 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1106 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1135 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1153 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1161 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1167 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1173 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1181 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1221 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1228 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1233 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1238 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1244 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1273 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (555 more lines truncated)

POST /ingest

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1046 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1061 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1069 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1099 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1140 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1149 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1154 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1161 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1167 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1177 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1206 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1224 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1232 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1238 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1244 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1252 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1292 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1299 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1304 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1309 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1315 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1344 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:354 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:417 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:440 (handler: query)

def query(req: QueryRequest) -> dict:
    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
            return {
                "response": _math_result["answer"],
                "answer": _math_result["answer"],
                "answer_sentences": [], "answer_sources": [],
                "answer_qtype": "computed", "is_question": True,
                "results": {"query": req.prompt, "local": [], "web": [],
# ... (421 more lines truncated)

POST /ingest

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:883 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:898 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:906 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:936 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:977 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:986 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:991 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:998 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1004 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1014 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1043 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1061 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1069 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1075 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1081 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1089 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1129 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1136 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1141 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1146 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1152 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1181 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:387 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:450 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:473 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # AEGIS-FIX: disambiguation gate.
    # Runs before teach/math/units so ambiguous definition queries are
    # intercepted before any heavy pipeline. detect_ambiguity() only
    # fires on definition-shaped prompts (subject extraction rejects
    # everything else), so this is safe for all other query types.
    if getattr(config, "ENABLE_DISAMBIGUATION", False):
        try:
            import disambiguate as _dis
            import session_store as _sess
            from web_ingest import fetch_wikipedia_summary as _wk_sum

            # ── Resolution branch: user already picked a sense ─────
            if req.sense:
                _subject = _dis.extract_subject(req.prompt) or ""
# ... (825 more lines truncated)

POST /ingest

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1320 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1335 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1343 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1373 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1414 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1423 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1428 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1435 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1441 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1451 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1480 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1498 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1506 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1512 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1518 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1526 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1566 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1573 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1578 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1583 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1589 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1618 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:387 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:450 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:473 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # AEGIS-FIX: disambiguation gate. See disambiguation_route.py.
    # Returns None to fall through (req.prompt may be rewritten), or an
    # "ambiguous" response dict to render the choice overlay.
    _dis_resp = disambiguation_route.intercept(req)
    if _dis_resp is not None:
        return _dis_resp

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
# ... (602 more lines truncated)

POST /ingest

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1097 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1112 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1120 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1150 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1191 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1200 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1205 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1212 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1218 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1228 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1257 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1275 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1283 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1289 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1295 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1303 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1343 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1350 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1355 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1360 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1366 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1395 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (430 more lines truncated)

POST /ingest

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:921 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:936 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:944 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:974 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1015 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1024 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1029 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1036 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1042 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1052 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1081 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1099 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1107 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1113 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1119 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1127 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1167 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1174 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1179 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1184 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1190 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1219 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (682 more lines truncated)

POST /ingest

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1175 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1190 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1198 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1228 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1269 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1278 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1283 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1290 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1296 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1306 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1335 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1353 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1361 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1367 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1373 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1381 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1421 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1428 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1433 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1438 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1444 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1473 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/path-a-20260913-152743/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/path-a-20260913-152743/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/path-a-20260913-152743/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (711 more lines truncated)

POST /ingest

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1204 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1219 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1227 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1257 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1298 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1307 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1312 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1319 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1325 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1335 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1364 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1382 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1390 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1396 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1402 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1410 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1450 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1457 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1462 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1467 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1473 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/path-a-20260913-152743/main.py:1502 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (660 more lines truncated)

POST /ingest

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1153 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1168 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1176 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1206 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1247 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1256 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1261 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1268 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1274 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1284 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1313 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1331 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1339 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1345 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1351 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1359 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1399 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1406 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1411 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1416 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1422 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1451 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (660 more lines truncated)

POST /ingest

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1153 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1168 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1176 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1206 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1247 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1256 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1261 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1268 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1274 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1284 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1313 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1331 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1339 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1345 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1351 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1359 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1399 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1406 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1411 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1416 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1422 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1451 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (660 more lines truncated)

POST /ingest

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1153 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1168 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1176 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1206 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1247 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1256 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1261 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1268 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1274 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1284 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1313 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1331 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1339 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1345 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1351 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1359 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1399 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1406 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1411 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1416 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1422 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1451 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

POST /tutorial/evolve

./.aegis-doctor/backups/teach-fix-20260912-214644/tutorials.py:230 (handler: _evolve)

    def _evolve(req: EvolveRequest):
        import teach
        topic = req.topic.strip()
        if not topic:
            return {"ok": False, "error": "topic required"}
        sources = []
        try:
            if teach._is_howto(topic) or any(t in topic.lower() for t in teach._TECHS):
                sources += teach.fetch_devto(topic, limit=4)
                sources += teach.fetch_github(topic, limit=3)
            sources += teach.fetch_stackexchange(topic, limit=4)
            sources += teach.fetch_wikipedia(topic)
            if len(sources) < 3:
                sources += teach.fetch_web_fallback(topic)
        except Exception as e:
            return {"ok": False, "error": f"source gather failed: {e}"}

        for s in sources:
            s["_r"] = teach._relevance_score(s, topic)
        sources.sort(key=lambda x: x["_r"], reverse=True)
        sources = [s for s in sources if s["_r"] >= 0.15][:8]
# ... (75 more lines truncated)

POST /tutorial/store

./.aegis-doctor/backups/teach-fix-20260912-214644/tutorials.py:274 (handler: _store)

    def _store(req: StoreRequest):
        try:
            doc_id = _save_tutorial(req.topic, req.raw, notes=req.notes)
            return {"ok": True, "doc_id": doc_id}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    @app.get("/tutorial/history/{topic}")
    def _history(topic: str):
        import teach, duckdb, config
        doc_id = teach._topic_key(topic)
        try:
            con = duckdb.connect(config.DUCKDB_PATH)
            rows = con.execute(
                "SELECT version, created_at, length(tutorial) "
                "FROM tutorial_versions WHERE doc_id=? ORDER BY version DESC",
                [doc_id]).fetchall()
            con.close()
            return {"ok": True, "versions": [
                {"version": r[0], "created_at": r[1], "chars": r[2]}
                for r in rows]}
# ... (31 more lines truncated)

GET /tutorial/history/{topic}

./.aegis-doctor/backups/teach-fix-20260912-214644/tutorials.py:282 (handler: _history)

    def _history(topic: str):
        import teach, duckdb, config
        doc_id = teach._topic_key(topic)
        try:
            con = duckdb.connect(config.DUCKDB_PATH)
            rows = con.execute(
                "SELECT version, created_at, length(tutorial) "
                "FROM tutorial_versions WHERE doc_id=? ORDER BY version DESC",
                [doc_id]).fetchall()
            con.close()
            return {"ok": True, "versions": [
                {"version": r[0], "created_at": r[1], "chars": r[2]}
                for r in rows]}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    @app.get("/tutorial/latest/{topic}")
    def _latest(topic: str):
        import teach
        prev = teach._latest_version(topic)
        if not prev:
# ... (23 more lines truncated)

GET /tutorial/latest/{topic}

./.aegis-doctor/backups/teach-fix-20260912-214644/tutorials.py:299 (handler: _latest)

    def _latest(topic: str):
        import teach
        prev = teach._latest_version(topic)
        if not prev:
            return {"ok": False, "error": "no stored tutorial"}
        parsed = parse_tutorial(prev["tutorial"])
        parsed["ok"] = True
        parsed["version"] = prev["version"]
        parsed["created_at"] = prev["created_at"]
        return parsed

    @app.post("/tutorial/generate")
    def _generate(req: EvolveRequest):
        import teach
        topic = req.topic.strip()
        if not topic:
            return {"ok": False, "error": "topic required"}
        try:
            tr = teach.teach_me(topic)
        except Exception as e:
            return {"ok": False, "error": str(e)}
# ... (6 more lines truncated)

POST /tutorial/generate

./.aegis-doctor/backups/teach-fix-20260912-214644/tutorials.py:311 (handler: _generate)

    def _generate(req: EvolveRequest):
        import teach
        topic = req.topic.strip()
        if not topic:
            return {"ok": False, "error": "topic required"}
        try:
            tr = teach.teach_me(topic)
        except Exception as e:
            return {"ok": False, "error": str(e)}
        if tr.get("tutorial"):
            parsed = parse_tutorial(tr["tutorial"])
            parsed["ok"] = True
            parsed["topic"] = topic
            return parsed
        return {"ok": False, "error": tr.get("tutorial_error", "generation failed")}

GET /

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:311 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(f.read())


# ---- Fresh-info intent detection ----
_CURRENT_INTENT_WORDS = {
    "price", "prices", "quote", "quotes", "rate", "rates",
    "spot", "level", "levels", "value", "values", "yield", "yields",
    "worth", "cost", "going", "today", "tonight", "tomorrow",
# ... (6 more lines truncated)

GET /health

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:356 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:379 (handler: query)

def query(req: QueryRequest) -> dict:
    _unit_result = None
    try:
        session_log.log("query", f"prompt={req.prompt!r}")
    except Exception:
        pass
    try:
        _unit_result = units.try_compute(req.prompt)
        if _unit_result:
            print(f"[Aegis] Units: {_unit_result['answer']}")
    except Exception as _exc:
        print(f"[Aegis] Units error: {_exc}")

    # Stock price lookup — runs before the main pipeline
    _stock_result = None
    if not _unit_result:
        try:
            _stock_result = stock.try_compute(req.prompt)
            if _stock_result:
                print(f"[Aegis] Stock: {_stock_result['answer']}")
        except Exception as _exc:
# ... (385 more lines truncated)

POST /ingest

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:786 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:801 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:809 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:839 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:880 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:889 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:894 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:901 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:907 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:917 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:946 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:964 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:972 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:978 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:984 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:992 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:1032 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript")

GET /boot/status

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:1039 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:1044 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:1049 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:1055 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:1084 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (664 more lines truncated)

POST /ingest

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1157 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1172 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1180 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1210 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1251 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1260 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1265 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1272 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1278 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1288 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1317 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1335 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1343 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1349 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1355 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1363 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1403 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1410 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1415 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1420 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1426 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1455 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (919 more lines truncated)

POST /ingest

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1442 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1457 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1465 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1495 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1536 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1545 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1550 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1557 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1563 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1573 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1602 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1620 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1628 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1641 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1661 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1680 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1686 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1691 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1697 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1703 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1711 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1751 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1758 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1763 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1768 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1774 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1803 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (907 more lines truncated)

POST /ingest

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1430 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1445 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1453 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1483 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1524 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1533 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1538 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1545 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1551 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1561 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1590 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1608 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1616 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1629 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1649 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1668 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1674 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1679 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1685 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1691 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1699 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1739 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1746 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1751 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1756 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1762 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1791 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/fix-r3-1789328611/main.py:316 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/fix-r3-1789328611/main.py:379 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/fix-r3-1789328611/main.py:402 (handler: query)

def query(req: QueryRequest) -> dict:
    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
            return {
                "response": _math_result["answer"],
                "answer": _math_result["answer"],
                "answer_sentences": [], "answer_sources": [],
                "answer_qtype": "computed", "is_question": True,
                "results": {"query": req.prompt, "local": [], "web": [],
# ... (421 more lines truncated)

POST /ingest

./.aegis-doctor/backups/fix-r3-1789328611/main.py:845 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/fix-r3-1789328611/main.py:860 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/fix-r3-1789328611/main.py:868 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/fix-r3-1789328611/main.py:898 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/fix-r3-1789328611/main.py:939 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/fix-r3-1789328611/main.py:948 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/fix-r3-1789328611/main.py:953 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/fix-r3-1789328611/main.py:960 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/fix-r3-1789328611/main.py:966 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/fix-r3-1789328611/main.py:976 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1005 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1023 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1031 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1037 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1043 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1051 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1091 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1098 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1103 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1108 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1114 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/fix-r3-1789328611/main.py:1143 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (610 more lines truncated)

POST /ingest

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1103 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1118 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1126 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1156 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1197 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1206 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1211 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1218 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1224 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1234 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1263 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1281 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1289 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1295 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1301 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1309 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1349 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1356 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1361 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1366 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1372 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1401 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/fix-all-1789326224/main.py:315 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/fix-all-1789326224/main.py:378 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/fix-all-1789326224/main.py:401 (handler: query)

def query(req: QueryRequest) -> dict:
    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    _unit_result = None
    try:
        session_log.log("query", f"prompt={req.prompt!r}")
    except Exception:
        pass
    try:
        _unit_result = units.try_compute(req.prompt)
        if _unit_result:
            print(f"[Aegis] Units: {_unit_result['answer']}")
    except Exception as _exc:
# ... (402 more lines truncated)

POST /ingest

./.aegis-doctor/backups/fix-all-1789326224/main.py:825 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/fix-all-1789326224/main.py:840 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/fix-all-1789326224/main.py:848 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/fix-all-1789326224/main.py:878 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/fix-all-1789326224/main.py:919 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/fix-all-1789326224/main.py:928 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/fix-all-1789326224/main.py:933 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/fix-all-1789326224/main.py:940 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/fix-all-1789326224/main.py:946 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/fix-all-1789326224/main.py:956 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/fix-all-1789326224/main.py:985 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/fix-all-1789326224/main.py:1003 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/fix-all-1789326224/main.py:1011 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/fix-all-1789326224/main.py:1017 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/fix-all-1789326224/main.py:1023 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/fix-all-1789326224/main.py:1031 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/fix-all-1789326224/main.py:1071 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/fix-all-1789326224/main.py:1078 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/fix-all-1789326224/main.py:1083 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/fix-all-1789326224/main.py:1088 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/fix-all-1789326224/main.py:1094 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/fix-all-1789326224/main.py:1123 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (1003 more lines truncated)

POST /ingest

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1526 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1541 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1549 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1579 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1620 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1629 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1634 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1641 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1647 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1657 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1686 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1704 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1712 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1725 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1745 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1764 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1770 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1775 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1781 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1787 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1795 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1835 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1842 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1847 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1852 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1858 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1887 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (610 more lines truncated)

POST /ingest

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1103 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1118 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1126 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1156 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1197 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1206 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1211 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1218 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1224 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1234 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1263 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1281 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1289 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1295 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1301 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1309 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1349 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1356 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1361 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1366 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1372 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1401 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (1050 more lines truncated)

POST /ingest

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1573 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1588 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1596 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1626 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1667 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1676 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1681 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1688 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1694 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1704 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1733 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1751 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1759 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1772 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1792 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1811 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1817 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1822 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1828 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1834 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1842 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1882 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1889 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1894 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1899 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1905 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1934 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (682 more lines truncated)

POST /ingest

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1175 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1190 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1198 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1228 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1269 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1278 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1283 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1290 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1296 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1306 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1335 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1353 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1361 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1367 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1373 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1381 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1421 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1428 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1433 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1438 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1444 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1473 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (555 more lines truncated)

POST /ingest

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1046 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1061 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1069 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1099 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1140 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1149 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1154 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1161 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1167 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1177 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1206 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1224 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1232 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1238 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1244 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1252 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1292 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1299 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1304 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1309 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1315 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1344 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:388 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:451 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:474 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: terminal sense resolution in query.
    # When req.sense is set, the user has explicitly picked a sense.
    # We resolve it directly from the wiktionary doc and return
    # immediately — bypassing the cache, the disambiguation gate, and
    # the entire pipeline. Nothing downstream can overwrite the answer.
    # AEGIS-FIX: multi-token subject terminal.
    # Also fires when the classifier extracts a multi-token subject
    # (e.g. "Apple Inc", "Barack Obama") even without an explicit sense
    # field. Multi-token subjects are already specific — the user
    # disambiguated by typing them — so if we have a wiktionary doc for
    # exactly that subject, return it directly.
    _terminal_subject = None
    if getattr(req, "sense", None):
        _terminal_subject = req.sense.replace("_", " ").title()
    else:
        try:
            import definition_path as _dp_probe
            _probe = _dp_probe.classify(req.prompt)
            _psubj = _probe.get("subject") or ""
            if _probe.get("is_definition") and _psubj and " " in _psubj:
# ... (694 more lines truncated)

POST /ingest

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1191 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1206 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1214 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1244 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1285 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1294 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1299 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1306 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1312 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1322 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1351 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1369 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1377 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1390 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

GET /debug/snapshot

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1399 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1405 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1411 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1419 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1459 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1466 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1471 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1476 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1482 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1511 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (1015 more lines truncated)

POST /ingest

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1538 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1553 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1561 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1591 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1632 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1641 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1646 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1653 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1659 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1669 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1698 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1716 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1724 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1737 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1757 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1776 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1782 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1787 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1793 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1799 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1807 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1847 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1854 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1859 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1864 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1870 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1899 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (448 more lines truncated)

POST /ingest

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:939 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:954 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:962 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:992 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1033 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1042 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1047 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1054 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1060 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1070 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1099 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1117 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1125 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1131 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1137 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1145 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1185 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1192 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1197 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1202 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1208 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1237 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:387 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:450 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:473 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: terminal sense resolution in query.
    # When req.sense is set, the user has explicitly picked a sense.
    # We resolve it directly from the wiktionary doc and return
    # immediately — bypassing the cache, the disambiguation gate, and
    # the entire pipeline. Nothing downstream can overwrite the answer.
    if getattr(req, "sense", None):
        try:
            import definition_path as _dp
            from web_ingest import ensure_wiktionary_seed
            _sense_title = req.sense.replace("_", " ").title()
            try:
                ensure_wiktionary_seed(_sense_title)
            except Exception as _e:
                print(f"[Aegis] Sense seed skipped: {_e}")
            _direct = _dp.direct_sense_answer(_sense_title)
            if _direct:
                print(f"[Aegis] Terminal sense resolution: "
                      f"{_sense_title!r} ({len(_direct)} chars)")
                return {
                    "response": _direct,
# ... (646 more lines truncated)

POST /ingest

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1141 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1156 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1164 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1194 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1235 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1244 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1249 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1256 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1262 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1272 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1301 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1319 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1327 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1333 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1339 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1347 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1387 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1394 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1399 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1404 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1410 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1439 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:392 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:455 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:478 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (789 more lines truncated)

POST /ingest

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1290 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1305 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1313 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1343 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1384 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1393 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1398 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1405 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1411 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1421 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1450 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1468 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1476 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1489 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1509 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1528 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1534 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1539 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1545 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1551 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1559 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1599 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1606 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1611 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1616 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1622 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1651 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

POST /tutorial/generate

./.aegis-doctor/backups/streaming-20260912-215458/tutorials.py:469 (handler: _generate)

    def _generate(req: EvolveRequest):
        topic = req.topic.strip()
        if not topic:
            return {"ok": False, "error": "topic required"}
        sources = _gather_sources(topic)
        if not sources:
            return {"ok": False, "error": "no sources found"}
        result = generate_natural_tutorial(topic, sources)
        if result.get("ok"):
            try:
                _save_tutorial(topic, result["raw"], notes="initial")
            except Exception as e:
                result["store_warning"] = str(e)
        return result

    @app.post("/tutorial/evolve")
    def _evolve(req: EvolveRequest):
        import teach
        topic = req.topic.strip()
        if not topic:
            return {"ok": False, "error": "topic required"}
# ... (52 more lines truncated)

POST /tutorial/evolve

./.aegis-doctor/backups/streaming-20260912-215458/tutorials.py:485 (handler: _evolve)

    def _evolve(req: EvolveRequest):
        import teach
        topic = req.topic.strip()
        if not topic:
            return {"ok": False, "error": "topic required"}
        sources = _gather_sources(topic)
        if not sources:
            return {"ok": False, "error": "no sources found"}
        prev = teach._latest_version(topic)
        prev_md = prev.get("tutorial") or ""
        prev_v = prev.get("version", 0)
        result = evolve_natural_tutorial(
            topic, sources, prev_md, previous_version=prev_v)
        if not result.get("ok"):
            return result
        try:
            _save_tutorial(topic, result["raw"], notes="evolved")
        except Exception as e:
            result["store_warning"] = str(e)
        return result

# ... (36 more lines truncated)

POST /tutorial/store

./.aegis-doctor/backups/streaming-20260912-215458/tutorials.py:507 (handler: _store)

    def _store(req: StoreRequest):
        try:
            doc_id = _save_tutorial(req.topic, req.raw, notes=req.notes)
            return {"ok": True, "doc_id": doc_id}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    @app.get("/tutorial/history/{topic}")
    def _history(topic: str):
        import teach, duckdb, config
        doc_id = teach._topic_key(topic)
        try:
            con = duckdb.connect(config.DUCKDB_PATH)
            rows = con.execute(
                "SELECT version, created_at, length(tutorial) "
                "FROM tutorial_versions WHERE doc_id=? "
                "ORDER BY version DESC", [doc_id]).fetchall()
            con.close()
            return {"ok": True, "versions": [
                {"version": r[0], "created_at": r[1], "chars": r[2]}
                for r in rows]}
# ... (14 more lines truncated)

GET /tutorial/history/{topic}

./.aegis-doctor/backups/streaming-20260912-215458/tutorials.py:515 (handler: _history)

    def _history(topic: str):
        import teach, duckdb, config
        doc_id = teach._topic_key(topic)
        try:
            con = duckdb.connect(config.DUCKDB_PATH)
            rows = con.execute(
                "SELECT version, created_at, length(tutorial) "
                "FROM tutorial_versions WHERE doc_id=? "
                "ORDER BY version DESC", [doc_id]).fetchall()
            con.close()
            return {"ok": True, "versions": [
                {"version": r[0], "created_at": r[1], "chars": r[2]}
                for r in rows]}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    @app.get("/tutorial/latest/{topic}")
    def _latest(topic: str):
        import teach
        prev = teach._latest_version(topic)
        if not prev:
# ... (6 more lines truncated)

GET /tutorial/latest/{topic}

./.aegis-doctor/backups/streaming-20260912-215458/tutorials.py:532 (handler: _latest)

    def _latest(topic: str):
        import teach
        prev = teach._latest_version(topic)
        if not prev:
            return {"ok": False, "error": "no stored tutorial"}
        parsed = parse_tutorial(prev["tutorial"])
        parsed["ok"] = True
        parsed["version"] = prev["version"]
        parsed["created_at"] = prev["created_at"]
        return parsed

GET /

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (447 more lines truncated)

POST /ingest

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:938 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:953 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:961 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:991 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1032 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1041 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1046 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1053 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1059 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1069 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1098 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1116 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1124 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1130 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1136 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1144 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1184 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1191 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1196 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1201 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1207 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1236 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (712 more lines truncated)

POST /ingest

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1205 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1220 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1228 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1258 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1299 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1308 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1313 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1320 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1326 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1336 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1365 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1383 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1391 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1397 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1403 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1411 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1451 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1458 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1463 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1468 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1474 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1503 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (411 more lines truncated)

POST /ingest

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:902 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:917 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:925 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:955 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:996 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1005 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1010 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1017 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1023 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1033 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1062 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1080 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1088 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1094 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1100 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1108 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1148 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1155 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1160 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1165 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1171 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1200 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (712 more lines truncated)

POST /ingest

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1205 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1220 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1228 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1258 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1299 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1308 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1313 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1320 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1326 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1336 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1365 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1383 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1391 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1397 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1403 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1411 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1451 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1458 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1463 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1468 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1474 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1503 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (713 more lines truncated)

POST /ingest

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1206 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1221 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1229 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1259 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1300 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1309 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1314 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1321 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1327 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1337 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1366 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1384 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1392 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1398 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1404 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1412 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1452 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1459 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1464 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1469 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1475 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1504 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:387 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:450 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:473 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # AEGIS-FIX: disambiguation gate.
    # Runs before teach/math/units so ambiguous definition queries are
    # intercepted before any heavy pipeline. detect_ambiguity() only
    # fires on definition-shaped prompts (subject extraction rejects
    # everything else), so this is safe for all other query types.
    if getattr(config, "ENABLE_DISAMBIGUATION", False):
        try:
            import disambiguate as _dis
            import session_store as _sess
            from web_ingest import (
                fetch_wikipedia_summary as _wk_sum,
                fetch_disambiguation_candidates as _wk_cands,
            )

# ... (829 more lines truncated)

POST /ingest

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1324 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1339 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1347 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1377 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1418 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1427 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1432 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1439 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1445 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1455 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1484 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1502 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1510 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1516 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1522 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1530 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1570 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1577 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1582 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1587 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1593 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1622 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (995 more lines truncated)

POST /ingest

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1518 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1533 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1541 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1571 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1612 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1621 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1626 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1633 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1639 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1649 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1678 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1696 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1704 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1717 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1737 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1756 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1762 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1767 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1773 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1779 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1787 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1827 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1834 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1839 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1844 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1850 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1879 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (555 more lines truncated)

POST /ingest

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1046 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1061 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1069 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1099 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1140 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1149 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1154 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1161 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1167 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1177 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1206 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1224 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1232 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1238 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1244 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1252 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1292 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1299 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1304 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1309 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1315 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1344 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:386 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:449 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:472 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # AEGIS-FIX: disambiguation gate.
    # Runs before teach/math/units so ambiguous definition queries are
    # intercepted before any heavy pipeline. detect_ambiguity() only
    # fires on definition-shaped prompts (subject extraction rejects
    # everything else), so this is safe for all other query types.
    if getattr(config, "ENABLE_DISAMBIGUATION", False):
        try:
            import disambiguate as _dis
            import session_store as _sess
            from web_ingest import (
                fetch_wikipedia_summary as _wk_sum,
                fetch_disambiguation_candidates as _wk_cands,
            )

# ... (738 more lines truncated)

POST /ingest

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1232 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1247 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1255 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1285 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1326 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1335 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1340 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1347 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1353 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1363 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1392 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1410 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1418 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1424 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1430 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1438 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1478 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1485 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1490 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1495 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1501 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1530 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (555 more lines truncated)

POST /ingest

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1046 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1061 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1069 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1099 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1140 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1149 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1154 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1161 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1167 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1177 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1206 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1224 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1232 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1238 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1244 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1252 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1292 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1299 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1304 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1309 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1315 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1344 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (409 more lines truncated)

POST /ingest

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:900 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:915 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:923 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:953 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:994 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1003 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1008 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1015 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1021 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1031 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1060 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1078 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1086 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1092 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1098 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1106 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1146 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1153 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1158 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1163 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1169 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1198 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (894 more lines truncated)

POST /ingest

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1417 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1432 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1440 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1470 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1511 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1520 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1525 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1532 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1538 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1548 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1577 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1595 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1603 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1616 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1636 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1655 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1661 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1666 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1672 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1678 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1686 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1726 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1733 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1738 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1743 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1749 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1778 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:389 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:452 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:475 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (729 more lines truncated)

POST /ingest

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1227 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1242 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1250 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1280 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1321 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1330 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1335 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1342 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1348 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1358 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1387 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1405 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1413 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1426 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1446 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1465 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1471 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1476 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1482 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1488 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1496 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1536 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1543 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1548 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1553 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1559 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1588 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:354 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:417 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:440 (handler: query)

def query(req: QueryRequest) -> dict:
    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
            return {
                "response": _math_result["answer"],
                "answer": _math_result["answer"],
                "answer_sentences": [], "answer_sources": [],
                "answer_qtype": "computed", "is_question": True,
                "results": {"query": req.prompt, "local": [], "web": [],
# ... (421 more lines truncated)

POST /ingest

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:883 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:898 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:906 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:936 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:977 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:986 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:991 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:998 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1004 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1014 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1043 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1061 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1069 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1075 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1081 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1089 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1129 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1136 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1141 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1146 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1152 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1181 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/query-log-20260913-170823/main.py:387 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/query-log-20260913-170823/main.py:450 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/query-log-20260913-170823/main.py:473 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: terminal sense resolution in query.
    # When req.sense is set, the user has explicitly picked a sense.
    # We resolve it directly from the wiktionary doc and return
    # immediately — bypassing the cache, the disambiguation gate, and
    # the entire pipeline. Nothing downstream can overwrite the answer.
    # AEGIS-FIX: multi-token subject terminal.
    # Also fires when the classifier extracts a multi-token subject
    # (e.g. "Apple Inc", "Barack Obama") even without an explicit sense
    # field. Multi-token subjects are already specific — the user
    # disambiguated by typing them — so if we have a wiktionary doc for
    # exactly that subject, return it directly.
    _terminal_subject = None
    if getattr(req, "sense", None):
        _terminal_subject = req.sense.replace("_", " ").title()
    else:
        try:
            import definition_path as _dp_probe
            _probe = _dp_probe.classify(req.prompt)
            _psubj = _probe.get("subject") or ""
            if _probe.get("is_definition") and _psubj and " " in _psubj:
# ... (694 more lines truncated)

POST /ingest

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1189 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1204 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1212 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1242 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1283 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1292 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1297 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1304 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1310 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1320 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1349 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1367 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1375 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1381 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1387 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1395 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1435 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1442 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1447 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1452 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1458 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/query-log-20260913-170823/main.py:1487 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (525 more lines truncated)

POST /ingest

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1016 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1031 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1039 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1069 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1110 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1119 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1124 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1131 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1137 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1147 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1176 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1194 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1202 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1208 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1214 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1222 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1262 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1269 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1274 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1279 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1285 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1314 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:414 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:477 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:500 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (1008 more lines truncated)

POST /ingest

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1531 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1546 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1554 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1584 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1625 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1634 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1639 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1646 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1652 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1662 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1691 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1709 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1717 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1730 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1750 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1769 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1775 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1780 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1786 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1792 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1800 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1840 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1847 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1852 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1857 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1863 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1892 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:387 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:450 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:473 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # AEGIS-FIX: disambiguation gate. See disambiguation_route.py.
    # Returns None to fall through (req.prompt may be rewritten), or an
    # "ambiguous" response dict to render the choice overlay.
    _dis_resp = disambiguation_route.intercept(req)
    if _dis_resp is not None:
        return _dis_resp

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
# ... (602 more lines truncated)

POST /ingest

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1097 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1112 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1120 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1150 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1191 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1200 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1205 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1212 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1218 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1228 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1257 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1275 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1283 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1289 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1295 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1303 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1343 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1350 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1355 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1360 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1366 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1395 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (630 more lines truncated)

POST /ingest

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1123 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1138 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1146 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1176 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1217 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1226 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1231 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1238 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1244 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1254 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1283 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1301 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1309 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1315 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1321 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1329 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1369 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1376 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1381 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1386 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1392 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1421 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (686 more lines truncated)

POST /ingest

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1179 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1194 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1202 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1232 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1273 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1282 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1287 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1294 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1300 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1310 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1339 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1357 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1365 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1371 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1377 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1385 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1425 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1432 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1437 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1442 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1448 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1477 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:385 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:448 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:471 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (711 more lines truncated)

POST /ingest

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1204 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1219 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1227 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1257 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1298 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1307 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1312 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1319 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1325 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1335 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1364 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1382 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1390 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1396 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1402 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1410 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1450 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1457 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1462 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1467 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1473 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1502 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:383 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:446 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:469 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # Teach short-circuit — must run before units/stock/local search
    try:
        _teach_resp = _tutorials.try_teach(req.prompt)
        if _teach_resp is not None:
            return _teach_resp
    except Exception as _te:
        print(f"[Aegis] teach short-circuit error: {_te}")
        import traceback as _tb
        _tb.print_exc()

    # ── Fast math path (arithmetic) ──
    try:
        _math_result = math_compute.try_compute(req.prompt)
        if _math_result:
# ... (610 more lines truncated)

POST /ingest

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1101 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1116 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1124 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1154 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1195 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1204 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1209 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1216 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1222 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1232 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1261 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1279 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1287 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1293 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1299 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1307 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1347 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1354 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1359 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1364 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1370 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1399 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:389 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:452 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:475 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: correction check goes first.
    # If the user has previously taught us the answer to this exact
    # prompt, return it immediately. This must run before terminal
    # sense resolution, disambiguation, cache, and the pipeline — a
    # user-taught answer is the highest authority in the system.
    if not getattr(req, "sense", None):
        try:
            _corr = query_corrections.get(req.prompt)
            if _corr:
                _ans = _corr["correct_answer"]
                print(f"[Aegis] User correction applied (top): "
                      f"{req.prompt!r} (used {_corr['used_count']}x)")
                return {
                    "response": _ans,
                    "answer": _ans,
                    "answer_sentences": [],
                    "answer_qtype": "user_correction",
                    "is_question": True,
                    "results": {"query": req.prompt, "local": [],
                                "web": [],
# ... (739 more lines truncated)

POST /ingest

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1237 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1252 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1260 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1290 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1331 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1340 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1345 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1352 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1358 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1368 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1397 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1415 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/query_log

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1423 (handler: api_query_log)

def api_query_log(limit: int = 50, only_bad: bool = False):
    """Recent queries. `only_bad=true` returns only thumbs-down rows."""
    return {"queries": query_log.recent(limit=limit,
                                         only_negative=only_bad)}

POST /query/feedback

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1436 (handler: api_query_feedback)

def api_query_feedback(req: FeedbackRequest):
    """Record a thumbs-up (+1) or thumbs-down (-1) for a query."""
    if req.value not in (-1, 1):
        raise HTTPException(400, "value must be +1 or -1")
    ok = query_log.set_feedback(req.session_id, req.prompt, req.value)
    return {"ok": ok}

POST /query/correct

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1456 (handler: api_query_correct)

def api_query_correct(req: CorrectionRequest):
    """Save a user correction. Subsequent identical prompts return the
    corrected answer directly without running the pipeline."""
    ok = query_corrections.save(
        prompt=req.prompt,
        original_answer=req.original_answer,
        correct_answer=req.correct_answer,
        session_id=req.session_id,
    )
    if not ok:
        raise HTTPException(400, "could not save correction")
    return {
        "ok": True,
        "message": "Correction saved. Same question will now "
                   "return your answer.",
    }

POST /correction/forget

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1475 (handler: api_correction_forget)

def api_correction_forget(req: ForgetRequest):
    ok = query_corrections.forget(req.prompt)
    return {"ok": ok}

GET /debug/corrections

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1481 (handler: api_debug_corrections)

def api_debug_corrections(limit: int = 50):
    return {"corrections": query_corrections.list_all(limit=limit)}

GET /debug/snapshot

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1486 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1492 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1498 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1506 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1546 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1553 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1558 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1563 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1569 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1598 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

GET /

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:386 (handler: serve_ui)

def serve_ui(loaded: str = "") -> HTMLResponse:
    # First browser hit triggers the boot sequence
    _st = boot.status()
    if loaded != "1" and not _st["complete"]:
        if not _st["started"]:
            boot.start_boot()
        loading = os.path.join(config.TEMPLATE_DIR, "loading.html")
        if os.path.exists(loading):
            with open(loading, "r", encoding="utf-8") as f:
                return HTMLResponse(f.read())
    if not os.path.exists(config.INDEX_HTML):
        raise HTTPException(500, f"UI template missing: {config.INDEX_HTML}")
    with open(config.INDEX_HTML, "r", encoding="utf-8") as f:
        return HTMLResponse(
            f.read(),
            headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
                     "Pragma": "no-cache",
                     "Expires": "0"})


# ---- Fresh-info intent detection ----
# ... (10 more lines truncated)

GET /health

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:449 (handler: health_check)

def health_check() -> dict:
    # Report the actual mode based on whether Ollama is up and the
    # synthesis model is pulled.
    try:
        import synthesis
        if synthesis.is_available() and synthesis.model_pulled():
            mode = "llm-assisted"
        elif synthesis.is_available():
            mode = "llm-ready"  # ollama up but model not pulled
        else:
            mode = "no-llm"
    except Exception:
        mode = "no-llm"

    return {
        "status": "healthy",
        "mode": mode,
        "version": app.version,
        "web_search": config.ENABLE_WEB_SEARCH,
    }

# ... (1 more lines truncated)

POST /query

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:472 (handler: query)

def query(req: QueryRequest) -> dict:
    # AEGIS-FIX: cache check first — repeat prompts return instantly
    _cached = _qcache_get(req.prompt)
    if _cached is not None:
        print(f"[Aegis] Query cache hit: {req.prompt!r}")
        return _cached

    # AEGIS-FIX: disambiguation gate.
    # Runs before teach/math/units so ambiguous definition queries are
    # intercepted before any heavy pipeline. detect_ambiguity() only
    # fires on definition-shaped prompts (subject extraction rejects
    # everything else), so this is safe for all other query types.
    if getattr(config, "ENABLE_DISAMBIGUATION", False):
        try:
            import disambiguate as _dis
            import session_store as _sess
            from web_ingest import (
                fetch_wikipedia_summary as _wk_sum,
                fetch_disambiguation_candidates as _wk_cands,
            )

# ... (712 more lines truncated)

POST /ingest

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1206 (handler: api_ingest)

def api_ingest(req: IngestRequest):
    try:
        ingest_document(
            doc_id=req.doc_id,
            title=req.title,
            body=req.body,
            source=req.source,
            date=req.date,
        )
        return {"status": "ok", "doc_id": req.doc_id}
    except Exception as exc:
        raise HTTPException(500, str(exc))

POST /ingest/url

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1221 (handler: api_ingest_url)

def api_ingest_url(req: UrlIngestRequest):
    try:
        return ingest_url(req.url, snippet=req.snippet)
    except Exception as exc:
        raise HTTPException(500, str(exc))

GET /document/{doc_id:path}

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1229 (handler: api_get_document)

def api_get_document(doc_id: str):
    """Return the full stored body of a document by its id."""
    import duckdb
    try:
        con = duckdb.connect(config.DUCKDB_PATH)
        row = con.execute("""
            SELECT id, title, body, source, date, url
            FROM documents WHERE id = ?
        """, [doc_id]).fetchone()
        con.close()
        if not row:
            raise HTTPException(404, "document not found")
        return {
            "id": row[0], "title": row[1], "body": row[2],
            "source": row[3], "date": row[4], "url": row[5],
            "chars": len(row[2] or ""),
        }
    except HTTPException:
        raise
    except Exception as exc:
        raise HTTPException(500, str(exc))
# ... (2 more lines truncated)

POST /ingest/paste

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1259 (handler: api_ingest_paste)

def api_ingest_paste(req: PasteRequest):
    """Store user-pasted content in the local store."""
    import hashlib
    from datetime import datetime, timezone

    body = (req.body or "").strip()
    if len(body) < 20:
        raise HTTPException(400, "Content too short (min 20 chars)")

    doc_id = "paste::" + hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
    title = (req.title or "").strip() or body[:80].replace("\n", " ")
    date = datetime.now(timezone.utc).strftime("%Y-%m-%d")

    try:
        ingest_document(
            doc_id=doc_id,
            title=title,
            body=body,
            source=req.source or "pasted",
            date=date,
            url="",
# ... (12 more lines truncated)

POST /crawl

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1300 (handler: api_crawl)

def api_crawl(req: CrawlRequest):
    jid = jobs.enqueue("crawl", {
        "seed": req.seed, "depth": req.depth,
        "same_domain": req.same_domain, "max_pages": req.max_pages,
    })
    return {"job_id": jid, "status": "queued"}

GET /jobs

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1309 (handler: api_jobs)

def api_jobs(limit: int = 20):
    return {"jobs": jobs.list_recent(limit)}

GET /jobs/{jid}

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1314 (handler: api_job)

def api_job(jid: int):
    j = jobs.get(jid)
    if not j: raise HTTPException(404, "no such job")
    return j

POST /ttl/refresh

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1321 (handler: api_ttl_refresh)

def api_ttl_refresh():
    jid = jobs.enqueue("refresh-stale", {"limit": 20})
    return {"job_id": jid}

GET /ttl/stale

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1327 (handler: api_ttl_stale)

def api_ttl_stale(limit: int = 20):
    return {"stale": scheduler.find_stale(limit)}

POST /vectors/search

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1337 (handler: api_vector_search)

def api_vector_search(req: VectorSearchRequest):
    """Pure vector (TF-IDF feature-hash) search over chunks."""
    import duckdb
    qv = vectorize(req.query)
    if not np.any(qv):
        return {"chunks": []}
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            rows = con.execute(
                "SELECT id, doc_id, text, vec FROM chunks LIMIT 5000"
            ).fetchall()
        except Exception:
            return {"chunks": []}
    finally:
        con.close()
    scored = []
    for rid, doc_id, text, blob in rows:
        v = from_blob(blob)
        if v.shape != qv.shape: continue
        s = float(np.dot(qv, v))
# ... (7 more lines truncated)

GET /index/stats

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1366 (handler: api_index_stats)

def api_index_stats():
    import duckdb
    con = duckdb.connect(config.DUCKDB_PATH)
    try:
        try:
            n_chunks = con.execute("SELECT COUNT(*) FROM chunks").fetchone()[0]
        except Exception:
            n_chunks = 0
        try:
            n_meta = con.execute("SELECT COUNT(*) FROM doc_meta").fetchone()[0]
        except Exception:
            n_meta = 0
    finally:
        con.close()
    return {"chunks": int(n_chunks), "meta_rows": int(n_meta)}

GET /store/stats

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1384 (handler: api_store_stats)

def api_store_stats():
    return store_stats()


# ---------------------------------------------------------------------------
# CLI / launcher
# ---------------------------------------------------------------------------

GET /debug/snapshot

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1392 (handler: api_debug_snapshot)

def api_debug_snapshot():
    """Full JSON dump of system state — paste this into a bug report."""
    return debug_log.snapshot()

GET /debug/logs

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1398 (handler: api_debug_logs)

def api_debug_logs(n: int = 200):
    """Recent log lines only."""
    return {"count": n, "logs": debug_log.get_recent_logs(n)}

GET /activity

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1404 (handler: api_activity)

def api_activity(since: int = 0):
    return {
        "events": activity.since(since),
        "latest": activity.latest_id(),
    }

GET /log

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1412 (handler: api_log)

def api_log(lines: int = 500):
    """Return the tail of the session log."""
    import session_log as _sl
    p = _sl.path()
    if not p:
        return {"error": "no active session log"}
    try:
        with open(p, "r", encoding="utf-8") as f:
            all_lines = f.readlines()
        return {
            "path": p,
            "total_lines": len(all_lines),
            "lines": all_lines[-lines:],
        }
    except Exception as exc:
        return {"error": str(exc), "path": p}

GET /thinking.js

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1452 (handler: _serve_thinking_js)

def _serve_thinking_js():
    import os as _os
    _p = _os.path.join(config.TEMPLATE_DIR, "thinking.js")
    return _FileResponse(_p, media_type="application/javascript", headers={"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0"})

GET /boot/status

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1459 (handler: boot_status)

def boot_status():
    return boot.status()

POST /boot/retry

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1464 (handler: boot_retry)

def boot_retry():
    return boot.retry()

POST /boot/reset

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1469 (handler: boot_reset)

def boot_reset():
    boot.reset()
    return {"status": "reset"}

GET /favicon.ico

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1475 (handler: _serve_favicon)

def _serve_favicon():
    from fastapi.responses import FileResponse as _FR
    _p = os.path.join(config.IMAGES_DIR, config.LOGO_FILENAME)
    if os.path.exists(_p):
        return _FR(_p, media_type="image/jpeg")
    raise HTTPException(404, "favicon not found")

POST /search

./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1504 (handler: search_endpoint)

def search_endpoint(req: SearchRequest):
    """Traditional search results: local store + web links, no answer synthesis."""
    q = req.query.strip()
    if not q:
        raise HTTPException(400, "Query required")

    # Local BM25
    local_rows = []
    try:
        from local_search import search_duckdb as _lsq
        local_rows = _lsq(q, limit=req.limit)
    except Exception as exc:
        print(f"[Aegis] Search local error: {exc}")

    # Web (expanded)
    web_rows = []
    if req.web:
        try:
            web_rows = _expanded_search(q, num_results=req.limit)
        except Exception as exc:
            print(f"[Aegis] Search web error: {exc}")
# ... (51 more lines truncated)

2. Pydantic Models

QueryRequest (./main.py:354)

IngestRequest (./main.py:360)

UrlIngestRequest (./main.py:368)

PasteRequest (./main.py:1661)

CrawlRequest (./main.py:1701)

VectorSearchRequest (./main.py:1740)

FeedbackRequest (./main.py:1807)

CorrectionRequest (./main.py:1822)

ForgetRequest (./main.py:1829)

SearchRequest (./main.py:1969)

QueryRequest (./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:327)

IngestRequest (./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:333)

UrlIngestRequest (./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:341)

PasteRequest (./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1372)

CrawlRequest (./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1412)

VectorSearchRequest (./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1451)

SearchRequest (./.aegis-doctor/backups/rewrite-p1-deadcode-20260913-160424/main.py:1617)

QueryRequest (./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:325)

IngestRequest (./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:337)

PasteRequest (./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1113)

CrawlRequest (./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1153)

VectorSearchRequest (./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1192)

SearchRequest (./.aegis-doctor/backups/picker-copula-20260913-143908/main.py:1358)

QueryRequest (./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:327)

IngestRequest (./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:333)

UrlIngestRequest (./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:341)

PasteRequest (./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1207)

CrawlRequest (./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1247)

VectorSearchRequest (./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1286)

SearchRequest (./.aegis-doctor/backups/stock-terminal-20260913-170252/main.py:1452)

QueryRequest (./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:333)

IngestRequest (./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:339)

UrlIngestRequest (./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:347)

PasteRequest (./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1389)

CrawlRequest (./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1429)

VectorSearchRequest (./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1468)

FeedbackRequest (./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1535)

CorrectionRequest (./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1550)

ForgetRequest (./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1557)

SearchRequest (./.aegis-doctor/backups/nonsense-gate-20260913-201239/main.py:1697)

QueryRequest (./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:354)

IngestRequest (./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:368)

PasteRequest (./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1464)

CrawlRequest (./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1504)

VectorSearchRequest (./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1543)

FeedbackRequest (./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1610)

CorrectionRequest (./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1625)

ForgetRequest (./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1632)

SearchRequest (./.aegis-doctor/backups/nonsense-gate-fix-20260913-201609/main.py:1772)

QueryRequest (./.aegis-doctor/backups/correction-first-20260913-172823/main.py:329)

IngestRequest (./.aegis-doctor/backups/correction-first-20260913-172823/main.py:335)

UrlIngestRequest (./.aegis-doctor/backups/correction-first-20260913-172823/main.py:343)

PasteRequest (./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1274)

CrawlRequest (./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1314)

VectorSearchRequest (./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1353)

FeedbackRequest (./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1420)

CorrectionRequest (./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1435)

ForgetRequest (./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1442)

SearchRequest (./.aegis-doctor/backups/correction-first-20260913-172823/main.py:1582)

QueryRequest (./.aegis-doctor/backups/20260912-210258/main.py:253)

IngestRequest (./.aegis-doctor/backups/20260912-210258/main.py:257)

UrlIngestRequest (./.aegis-doctor/backups/20260912-210258/main.py:265)

PasteRequest (./.aegis-doctor/backups/20260912-210258/main.py:833)

CrawlRequest (./.aegis-doctor/backups/20260912-210258/main.py:873)

VectorSearchRequest (./.aegis-doctor/backups/20260912-210258/main.py:912)

SearchRequest (./.aegis-doctor/backups/20260912-210258/main.py:1078)

QueryRequest (./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:253)

IngestRequest (./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:257)

UrlIngestRequest (./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:265)

PasteRequest (./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:833)

CrawlRequest (./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:873)

VectorSearchRequest (./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:912)

SearchRequest (./.aegis-doctor/backups/tutorial-upgrade-20260912-213702/main.py:1078)

QueryRequest (./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:325)

IngestRequest (./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:337)

PasteRequest (./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1123)

CrawlRequest (./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1163)

VectorSearchRequest (./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1202)

SearchRequest (./.aegis-doctor/backups/wiktionary-phase1-20260913-144440/main.py:1368)

QueryRequest (./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:327)

IngestRequest (./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:339)

PasteRequest (./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1200)

CrawlRequest (./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1240)

VectorSearchRequest (./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1279)

SearchRequest (./.aegis-doctor/backups/picker-articles-20260913-145921/main.py:1445)

QueryRequest (./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:354)

IngestRequest (./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:368)

PasteRequest (./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1578)

CrawlRequest (./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1618)

VectorSearchRequest (./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1657)

FeedbackRequest (./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1724)

CorrectionRequest (./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1739)

ForgetRequest (./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1746)

SearchRequest (./.aegis-doctor/backups/units-nonsense-20260913-222755/main.py:1886)

QueryRequest (./.aegis-doctor/backups/all-three-20260913-210154/main.py:354)

IngestRequest (./.aegis-doctor/backups/all-three-20260913-210154/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/all-three-20260913-210154/main.py:368)

PasteRequest (./.aegis-doctor/backups/all-three-20260913-210154/main.py:1477)

CrawlRequest (./.aegis-doctor/backups/all-three-20260913-210154/main.py:1517)

VectorSearchRequest (./.aegis-doctor/backups/all-three-20260913-210154/main.py:1556)

FeedbackRequest (./.aegis-doctor/backups/all-three-20260913-210154/main.py:1623)

CorrectionRequest (./.aegis-doctor/backups/all-three-20260913-210154/main.py:1638)

ForgetRequest (./.aegis-doctor/backups/all-three-20260913-210154/main.py:1645)

SearchRequest (./.aegis-doctor/backups/all-three-20260913-210154/main.py:1785)

QueryRequest (./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:325)

IngestRequest (./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:337)

PasteRequest (./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1022)

CrawlRequest (./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1062)

VectorSearchRequest (./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1101)

SearchRequest (./.aegis-doctor/backups/defpath-v4-20260913-142442/main.py:1267)

QueryRequest (./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:325)

IngestRequest (./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:337)

PasteRequest (./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1093)

CrawlRequest (./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1133)

VectorSearchRequest (./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1172)

SearchRequest (./.aegis-doctor/backups/defpath-v6-retry-20260913-143222/main.py:1338)

QueryRequest (./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:296)

IngestRequest (./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:300)

UrlIngestRequest (./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:308)

PasteRequest (./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:930)

CrawlRequest (./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:970)

VectorSearchRequest (./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1009)

SearchRequest (./.aegis-doctor/backups/auto-fix-20260913-130338/main.py:1175)

QueryRequest (./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:327)

IngestRequest (./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:333)

UrlIngestRequest (./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:341)

PasteRequest (./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1367)

CrawlRequest (./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1407)

VectorSearchRequest (./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1446)

SearchRequest (./.aegis-doctor/backups/option2-step2-fix-20260913-154809/main.py:1612)

QueryRequest (./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:327)

IngestRequest (./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:333)

UrlIngestRequest (./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:341)

PasteRequest (./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1144)

CrawlRequest (./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1184)

VectorSearchRequest (./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1223)

SearchRequest (./.aegis-doctor/backups/sense-terminal-main-20260913-165625/main.py:1389)

QueryRequest (./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:325)

IngestRequest (./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:337)

PasteRequest (./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:968)

CrawlRequest (./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1008)

VectorSearchRequest (./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1047)

SearchRequest (./.aegis-doctor/backups/defpath-v2-picker-only-20260913-140703/main.py:1213)

QueryRequest (./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:327)

IngestRequest (./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:339)

PasteRequest (./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1222)

CrawlRequest (./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1262)

VectorSearchRequest (./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1301)

SearchRequest (./.aegis-doctor/backups/wkterm-init-20260913-151256/main.py:1467)

QueryRequest (./.aegis-doctor/backups/path-a-20260913-152743/main.py:327)

IngestRequest (./.aegis-doctor/backups/path-a-20260913-152743/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/path-a-20260913-152743/main.py:339)

PasteRequest (./.aegis-doctor/backups/path-a-20260913-152743/main.py:1251)

CrawlRequest (./.aegis-doctor/backups/path-a-20260913-152743/main.py:1291)

VectorSearchRequest (./.aegis-doctor/backups/path-a-20260913-152743/main.py:1330)

SearchRequest (./.aegis-doctor/backups/path-a-20260913-152743/main.py:1496)

QueryRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:327)

IngestRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:339)

PasteRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1200)

CrawlRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1240)

VectorSearchRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1279)

SearchRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150108/main.py:1445)

QueryRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:327)

IngestRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:339)

PasteRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1200)

CrawlRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1240)

VectorSearchRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1279)

SearchRequest (./.aegis-doctor/backups/picker-articles-v2-20260913-150126/main.py:1445)

QueryRequest (./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:327)

IngestRequest (./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:339)

PasteRequest (./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1200)

CrawlRequest (./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1240)

VectorSearchRequest (./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1279)

SearchRequest (./.aegis-doctor/backups/picker-articles-20260913-150232/main.py:1445)

QueryRequest (./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:253)

IngestRequest (./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:257)

UrlIngestRequest (./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:265)

PasteRequest (./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:833)

CrawlRequest (./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:873)

VectorSearchRequest (./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:912)

SearchRequest (./.aegis-doctor/backups/teach-fix-20260912-214644/main.py:1078)

QueryRequest (./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:327)

IngestRequest (./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:339)

PasteRequest (./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1204)

CrawlRequest (./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1244)

VectorSearchRequest (./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1283)

SearchRequest (./.aegis-doctor/backups/wk-shortcut-20260913-150709/main.py:1449)

QueryRequest (./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:354)

IngestRequest (./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:368)

PasteRequest (./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1489)

CrawlRequest (./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1529)

VectorSearchRequest (./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1568)

FeedbackRequest (./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1635)

CorrectionRequest (./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1650)

ForgetRequest (./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1657)

SearchRequest (./.aegis-doctor/backups/llm-cap-gate-20260913-211851/main.py:1797)

QueryRequest (./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:354)

IngestRequest (./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:368)

PasteRequest (./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1477)

CrawlRequest (./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1517)

VectorSearchRequest (./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1556)

FeedbackRequest (./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1623)

CorrectionRequest (./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1638)

ForgetRequest (./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1645)

SearchRequest (./.aegis-doctor/backups/item-5-stock-matcher-20260913-202415/main.py:1785)

QueryRequest (./.aegis-doctor/backups/fix-r3-1789328611/main.py:258)

IngestRequest (./.aegis-doctor/backups/fix-r3-1789328611/main.py:262)

UrlIngestRequest (./.aegis-doctor/backups/fix-r3-1789328611/main.py:270)

PasteRequest (./.aegis-doctor/backups/fix-r3-1789328611/main.py:892)

CrawlRequest (./.aegis-doctor/backups/fix-r3-1789328611/main.py:932)

VectorSearchRequest (./.aegis-doctor/backups/fix-r3-1789328611/main.py:971)

SearchRequest (./.aegis-doctor/backups/fix-r3-1789328611/main.py:1137)

QueryRequest (./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:327)

IngestRequest (./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:339)

PasteRequest (./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1150)

CrawlRequest (./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1190)

VectorSearchRequest (./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1229)

SearchRequest (./.aegis-doctor/backups/wiktionary-parsefix-20260913-145212/main.py:1395)

QueryRequest (./.aegis-doctor/backups/fix-all-1789326224/main.py:257)

IngestRequest (./.aegis-doctor/backups/fix-all-1789326224/main.py:261)

UrlIngestRequest (./.aegis-doctor/backups/fix-all-1789326224/main.py:269)

PasteRequest (./.aegis-doctor/backups/fix-all-1789326224/main.py:872)

CrawlRequest (./.aegis-doctor/backups/fix-all-1789326224/main.py:912)

VectorSearchRequest (./.aegis-doctor/backups/fix-all-1789326224/main.py:951)

SearchRequest (./.aegis-doctor/backups/fix-all-1789326224/main.py:1117)

QueryRequest (./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:354)

IngestRequest (./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:368)

PasteRequest (./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1573)

CrawlRequest (./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1613)

VectorSearchRequest (./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1652)

FeedbackRequest (./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1719)

CorrectionRequest (./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1734)

ForgetRequest (./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1741)

SearchRequest (./.aegis-doctor/backups/battery-round2-20260913-221020/main.py:1881)

QueryRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:327)

IngestRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:339)

PasteRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1150)

CrawlRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1190)

VectorSearchRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1229)

SearchRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144807/main.py:1395)

QueryRequest (./.aegis-doctor/backups/junk-top-20260913-224047/main.py:354)

IngestRequest (./.aegis-doctor/backups/junk-top-20260913-224047/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/junk-top-20260913-224047/main.py:368)

PasteRequest (./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1620)

CrawlRequest (./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1660)

VectorSearchRequest (./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1699)

FeedbackRequest (./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1766)

CorrectionRequest (./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1781)

ForgetRequest (./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1788)

SearchRequest (./.aegis-doctor/backups/junk-top-20260913-224047/main.py:1928)

QueryRequest (./.aegis-doctor/backups/wk-init-20260913-151051/main.py:327)

IngestRequest (./.aegis-doctor/backups/wk-init-20260913-151051/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/wk-init-20260913-151051/main.py:339)

PasteRequest (./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1222)

CrawlRequest (./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1262)

VectorSearchRequest (./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1301)

SearchRequest (./.aegis-doctor/backups/wk-init-20260913-151051/main.py:1467)

QueryRequest (./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:325)

IngestRequest (./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:337)

PasteRequest (./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1093)

CrawlRequest (./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1133)

VectorSearchRequest (./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1172)

SearchRequest (./.aegis-doctor/backups/defpath-v6-lines-20260913-143335/main.py:1338)

QueryRequest (./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:328)

IngestRequest (./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:334)

UrlIngestRequest (./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:342)

PasteRequest (./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1238)

CrawlRequest (./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1278)

VectorSearchRequest (./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1317)

FeedbackRequest (./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1384)

SearchRequest (./.aegis-doctor/backups/corrections-backend-20260913-171339/main.py:1505)

QueryRequest (./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:354)

IngestRequest (./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:368)

PasteRequest (./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1585)

CrawlRequest (./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1625)

VectorSearchRequest (./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1664)

FeedbackRequest (./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1731)

CorrectionRequest (./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1746)

ForgetRequest (./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1753)

SearchRequest (./.aegis-doctor/backups/junk-refuse-20260913-223732/main.py:1893)

QueryRequest (./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:325)

IngestRequest (./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:337)

PasteRequest (./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:986)

CrawlRequest (./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1026)

VectorSearchRequest (./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1065)

SearchRequest (./.aegis-doctor/backups/defpath-v3-strict-20260913-141243/main.py:1231)

QueryRequest (./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:327)

IngestRequest (./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:333)

UrlIngestRequest (./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:341)

PasteRequest (./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1188)

CrawlRequest (./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1228)

VectorSearchRequest (./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1267)

SearchRequest (./.aegis-doctor/backups/multitoken-terminal-20260913-165749/main.py:1433)

QueryRequest (./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:332)

IngestRequest (./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:338)

UrlIngestRequest (./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:346)

PasteRequest (./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1337)

CrawlRequest (./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1377)

VectorSearchRequest (./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1416)

FeedbackRequest (./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1483)

CorrectionRequest (./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1498)

ForgetRequest (./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1505)

SearchRequest (./.aegis-doctor/backups/step-3-relationships-20260913-195252/main.py:1645)

QueryRequest (./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:325)

IngestRequest (./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:337)

PasteRequest (./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:985)

CrawlRequest (./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1025)

VectorSearchRequest (./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1064)

SearchRequest (./.aegis-doctor/backups/dead-code-cleanup-20260913-134936/main.py:1230)

QueryRequest (./.aegis-doctor/backups/final-fix-20260913-151708/main.py:327)

IngestRequest (./.aegis-doctor/backups/final-fix-20260913-151708/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/final-fix-20260913-151708/main.py:339)

PasteRequest (./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1252)

CrawlRequest (./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1292)

VectorSearchRequest (./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1331)

SearchRequest (./.aegis-doctor/backups/final-fix-20260913-151708/main.py:1497)

QueryRequest (./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:325)

IngestRequest (./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:337)

PasteRequest (./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:949)

CrawlRequest (./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:989)

VectorSearchRequest (./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1028)

SearchRequest (./.aegis-doctor/backups/defpath-sentence-extract-20260913-140411/main.py:1194)

QueryRequest (./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:327)

IngestRequest (./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:339)

PasteRequest (./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1252)

CrawlRequest (./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1292)

VectorSearchRequest (./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1331)

SearchRequest (./.aegis-doctor/backups/drop-low-no-art-20260913-151902/main.py:1497)

QueryRequest (./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:327)

IngestRequest (./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:339)

PasteRequest (./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1253)

CrawlRequest (./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1293)

VectorSearchRequest (./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1332)

SearchRequest (./.aegis-doctor/backups/option2-step2-20260913-154457/main.py:1498)

QueryRequest (./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:327)

IngestRequest (./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:333)

UrlIngestRequest (./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:341)

PasteRequest (./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1371)

CrawlRequest (./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1411)

VectorSearchRequest (./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1450)

SearchRequest (./.aegis-doctor/backups/rewrite-p2-defpath-20260913-160800/main.py:1616)

QueryRequest (./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:354)

IngestRequest (./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:368)

PasteRequest (./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1565)

CrawlRequest (./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1605)

VectorSearchRequest (./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1644)

FeedbackRequest (./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1711)

CorrectionRequest (./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1726)

ForgetRequest (./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1733)

SearchRequest (./.aegis-doctor/backups/definition-routing-20260913-215542/main.py:1873)

QueryRequest (./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:325)

IngestRequest (./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:337)

PasteRequest (./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1093)

CrawlRequest (./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1133)

VectorSearchRequest (./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1172)

SearchRequest (./.aegis-doctor/backups/defpath-v6-20260913-143155/main.py:1338)

QueryRequest (./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:326)

IngestRequest (./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:332)

UrlIngestRequest (./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:340)

PasteRequest (./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1279)

CrawlRequest (./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1319)

VectorSearchRequest (./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1358)

SearchRequest (./.aegis-doctor/backups/remove-reapply-20260913-161147/main.py:1524)

QueryRequest (./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:325)

IngestRequest (./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:337)

PasteRequest (./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1093)

CrawlRequest (./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1133)

VectorSearchRequest (./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1172)

SearchRequest (./.aegis-doctor/backups/defpath-v6-20260913-142921/main.py:1338)

QueryRequest (./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:325)

IngestRequest (./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:337)

PasteRequest (./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:947)

CrawlRequest (./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:987)

VectorSearchRequest (./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1026)

SearchRequest (./.aegis-doctor/backups/defpath-threshold-20260913-135727/main.py:1192)

QueryRequest (./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:354)

IngestRequest (./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:368)

PasteRequest (./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1464)

CrawlRequest (./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1504)

VectorSearchRequest (./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1543)

FeedbackRequest (./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1610)

CorrectionRequest (./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1625)

ForgetRequest (./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1632)

SearchRequest (./.aegis-doctor/backups/nonsense-gate-v3-20260913-201932/main.py:1772)

QueryRequest (./.aegis-doctor/backups/step-1c-20260913-193019/main.py:329)

IngestRequest (./.aegis-doctor/backups/step-1c-20260913-193019/main.py:335)

UrlIngestRequest (./.aegis-doctor/backups/step-1c-20260913-193019/main.py:343)

PasteRequest (./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1274)

CrawlRequest (./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1314)

VectorSearchRequest (./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1353)

FeedbackRequest (./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1420)

CorrectionRequest (./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1435)

ForgetRequest (./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1442)

SearchRequest (./.aegis-doctor/backups/step-1c-20260913-193019/main.py:1582)

QueryRequest (./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:296)

IngestRequest (./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:300)

UrlIngestRequest (./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:308)

PasteRequest (./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:930)

CrawlRequest (./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:970)

VectorSearchRequest (./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1009)

SearchRequest (./.aegis-doctor/backups/what-is-fastpath-20260913-134911/main.py:1175)

QueryRequest (./.aegis-doctor/backups/query-log-20260913-170823/main.py:327)

IngestRequest (./.aegis-doctor/backups/query-log-20260913-170823/main.py:333)

UrlIngestRequest (./.aegis-doctor/backups/query-log-20260913-170823/main.py:341)

PasteRequest (./.aegis-doctor/backups/query-log-20260913-170823/main.py:1236)

CrawlRequest (./.aegis-doctor/backups/query-log-20260913-170823/main.py:1276)

VectorSearchRequest (./.aegis-doctor/backups/query-log-20260913-170823/main.py:1315)

SearchRequest (./.aegis-doctor/backups/query-log-20260913-170823/main.py:1481)

QueryRequest (./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:325)

IngestRequest (./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:337)

PasteRequest (./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1063)

CrawlRequest (./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1103)

VectorSearchRequest (./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1142)

SearchRequest (./.aegis-doctor/backups/defpath-v5-docopen-20260913-142727/main.py:1308)

QueryRequest (./.aegis-doctor/backups/units-temp-20260913-222920/main.py:354)

IngestRequest (./.aegis-doctor/backups/units-temp-20260913-222920/main.py:360)

UrlIngestRequest (./.aegis-doctor/backups/units-temp-20260913-222920/main.py:368)

PasteRequest (./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1578)

CrawlRequest (./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1618)

VectorSearchRequest (./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1657)

FeedbackRequest (./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1724)

CorrectionRequest (./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1739)

ForgetRequest (./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1746)

SearchRequest (./.aegis-doctor/backups/units-temp-20260913-222920/main.py:1886)

QueryRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:327)

IngestRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:333)

UrlIngestRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:341)

PasteRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1144)

CrawlRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1184)

VectorSearchRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1223)

SearchRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-162621/main.py:1389)

QueryRequest (./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:327)

IngestRequest (./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:339)

PasteRequest (./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1170)

CrawlRequest (./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1210)

VectorSearchRequest (./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1249)

SearchRequest (./.aegis-doctor/backups/qapool-promote-20260913-145721/main.py:1415)

QueryRequest (./.aegis-doctor/backups/final-fix-20260913-151652/main.py:327)

IngestRequest (./.aegis-doctor/backups/final-fix-20260913-151652/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/final-fix-20260913-151652/main.py:339)

PasteRequest (./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1226)

CrawlRequest (./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1266)

VectorSearchRequest (./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1305)

SearchRequest (./.aegis-doctor/backups/final-fix-20260913-151652/main.py:1471)

QueryRequest (./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:327)

IngestRequest (./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:331)

UrlIngestRequest (./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:339)

PasteRequest (./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1251)

CrawlRequest (./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1291)

VectorSearchRequest (./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1330)

SearchRequest (./.aegis-doctor/backups/line965-fix-20260913-152429/main.py:1496)

QueryRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:325)

IngestRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:329)

UrlIngestRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:337)

PasteRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1148)

CrawlRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1188)

VectorSearchRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1227)

SearchRequest (./.aegis-doctor/backups/wiktionary-decl-20260913-144735/main.py:1393)

QueryRequest (./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:329)

IngestRequest (./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:335)

UrlIngestRequest (./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:343)

PasteRequest (./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1284)

CrawlRequest (./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1324)

VectorSearchRequest (./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1363)

FeedbackRequest (./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1430)

CorrectionRequest (./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1445)

ForgetRequest (./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1452)

SearchRequest (./.aegis-doctor/backups/step-2-live-fastpaths-20260913-194632/main.py:1592)

QueryRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:326)

IngestRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:332)

UrlIngestRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:340)

PasteRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1253)

CrawlRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1293)

VectorSearchRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1332)

SearchRequest (./.aegis-doctor/backups/rewrite-p3-disroute-20260913-161411/main.py:1498)

3. Config / Env Vars

4. Database Sample Data

DuckDB: ./data/aegis.duckdb

Tables: doc_meta, documents, documents_quarantine, query_log, tutorial_versions, user_corrections


doc_meta  columns: ['doc_id', 'content_hash', 'fetched_at', 'ttl_days', 'last_refresh']
  sample (doc_id): []

documents  columns: ['id', 'title', 'body', 'source', 'date', 'url', 'content_hash']
  sample (id): [('web::133c8a7e89e10aed',), ('web::794b07d471662630',), ('web::32f14782350fe7d1',)]

documents_quarantine  columns: ['id', 'title', 'body', 'source', 'date', 'url', 'quarantine_reason', 'quarantined_at']
  sample (id): [('web::7c6c49d5ec5932b0',), ('web::1b7471db603b00ea',), ('web::85a57475092fcd5d',)]

query_log  columns: ['ts', 'prompt', 'qtype', 'answer', 'source', 'elapsed_ms', 'session_id', 'feedback']
  sample (session_id): [(None,), ('0d697f26-4a7a-43a2-a23b-f4c08b24d631',), (None,)]

tutorial_versions  columns: ['doc_id', 'version', 'topic', 'tutorial', 'created_at', 'source_hash']
  sample (doc_id): [('tutorial::df39f013364f9985',), ('tutorial::df39f013364f9985',), ('tutorial::12a5d18ee896e599',)]

user_corrections  columns: ['prompt_norm', 'original_prompt', 'original_answer', 'correct_answer', 'created_at', 'used_count', 'session_id']
  sample (session_id): [(None,), (None,)]

SQLite: ./data/jobs.sqlite

Tables: jobs, sqlite_sequence


jobs  columns: ['id', 'kind', 'params', 'status', 'created', 'started', 'finished', 'progress', 'total', 'message', 'result', 'error']
  sample (id): [(1,), (2,)]

sqlite_sequence  columns: ['name', 'seq']
  sample (name, seq): [('jobs', 2)]

_Discovery complete. Nothing was modified._