mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-08-05 10:55:29 +00:00
Updates handoff/progress/todos to reflect that M2 is committed and visually verified, and documents the three bugs found (and fixed) along the way: the memory_graph_routes.py owner-scoping mismatch, the detail panel's stuck `hidden` class, and search leaving stale selection-highlight opacity over its own matches.
14 KiB
14 KiB
Memory Graph View — Progress Log
Session-by-session record. Newest entry on top. See docs/todos.md for the live checklist and docs/handoff.md for the exact next action.
Session 4 — Milestone 2 verification, two bugs found and fixed, M2 committed
Goal: pick up exactly where Session 3 stopped — get a real, visual confirmation the Memory Graph tab works, then commit M2.
What was done
- Launched an isolated instance (
ODYSSEUS_DATA_DIR/DATABASE_URLin the session scratchpad,AUTH_ENABLED=false,LOCALHOST_BYPASS=true,CHROMADB_PORT=8100,APP_PORT=7010). ChromaDB was still reachable atlocalhost:8100as documented. FastEmbed model download completed this time (was cached from the aborted Session 3 attempt). - Seeded the exact 7-memory set from
docs/handoff.md's Session 3 plan viaPOST /api/memory/add, pinned one, and attempted the manual link between the two Lighthouse entries viaPOST /api/memory/{id}/links. - Found bug 1 (backend, Milestone 1 code): the link call 404'd and
GET /api/memory/graphreturned zero nodes despite 7 memories existing. Root cause:memory_graph_routes.pyusedrequire_user(request)(returns""in single-user/no-auth/localhost-bypass mode) for owner resolution, while every route inmemory_routes.pyuses a local_owner(request)=get_current_user(request)(returnsNonein that same mode).MemoryManager.load(owner=...)and_verify_memory_owner()both special-caseNoneas "no filter / bypass ownership check" — but""is notNone, soload(owner="")filtered strictly against entries that never gotowner=""stamped (sinceadd_entryonly sets theownerkey when it's truthy). Fixed by switching the graph and links routes to the same_owner()/get_current_user()pattern already used everywhere else in the memory routes (added a local_owner()helper tomemory_graph_routes.py, matchingmemory_routes.py's). Verified via curl: graph then returned all 7 nodes plus the expected similarity edge (0.875, between the near-duplicate identity pair) and the manual link edge. Committed separately from the M2 frontend work, since it's a fix to already-committed M1 code, not new M2 code. - Restarted the server (data survives — only the process was killed) and re-verified the fix, then moved to browser testing.
- Opened
/in Chrome, clicked "Memory Graph" in the sidebar Tools list. Modal rendered correctly: 7 nodes, similarity edge, manual link edge, category chips, search box, min-match slider, Link mode button, legend. - Found bug 2 (frontend): clicking a node correctly highlighted its neighborhood but no detail panel appeared. Traced to
static/js/memoryGraph.js: the panel div (#memory-graph-detail) is created with a hardcodedhiddenclass in the initial modal template, and_renderDetailPanel()only ever setpanel.innerHTML— nothing removed thehiddenclass on selection. Fixed with a one-linepanel.classList.remove('hidden')at the top of_renderDetailPanel(). Re-verified: panel now shows category tag, text, uses/pinned meta, timestamp, and Unpin/Edit/Start-link/Delete buttons on node click. - Found bug 3 (frontend): typing a search term didn't visually surface matches — matching nodes stayed at
opacity:0.08because a prior node-selection's.mg-dimmedclass (added by_highlightNeighborhood) was never cleared by_applySearch(), which only ever added/removed its own.mg-search-matchclass. Fixed by having_applySearch()clear_selectedId(resetting the detail panel) and stripmg-highlighted/mg-dimmedat the top of the function, so a fresh search cleanly supersedes any leftover selection state. Re-verified: searching "lighthouse" now shows all nodes at full opacity with the two matching nodes ringed. - Verified category chip filtering (isolating "identity" correctly showed only the 2 identity nodes), the min-match similarity slider (raising it above 0.875 correctly hid the identity-pair similarity edge), link-mode's two-click create flow end-to-end through the actual UI (new manual edge appeared after the automatic post-mutation reload, proving the bug-1 fix works from the UI path too, not just curl), the inline Edit textarea (Save/Cancel), and a theme switch (light theme via the Theme modal — all non-canvas chrome recolored live via CSS variables as expected; canvas node fill recompute-on-render-only limitation, already documented, was reconfirmed and left as a Milestone 3 item rather than fixed now).
- Cleanup: deleted all 7 seeded memories via the real
DELETE /api/memory/{id}endpoint. Queried the shared Chromaodysseus_memories_fastembedcollection directly (POST .../collections/{id}/getwith the 7 ids) and confirmed zero vectors remained — symmetric cleanup verified, not just assumed. Killed the server by resolving the actual listening PID viaGet-NetTCPConnection -LocalPort 7010 -State Listen(not a guessed PID or shell job number — confirmed this matters: the venv'spython.exere-execs into a different on-disk interpreter path, soGet-CimInstance ... -Filter "Name='python.exe'"alone returns multiple candidates and only the actual socket owner viaGet-NetTCPConnectiondisambiguates which one to kill). - Committed as 4 commits: the pre-existing
agent_loop.pyimport fix (standalone, per Session 3's flag not to fold it silently into a feature commit), the M1 owner-scoping fix (standalone), the M2 frontend (module + vendored Cytoscape + HTML/app.js/init.js wiring + CSS, one commit), and this docs update.
Files changed this session
| File | Change |
|---|---|
routes/memory/memory_graph_routes.py |
owner-resolution bug fix (bug 1) |
static/js/memoryGraph.js |
detail-panel visibility fix (bug 2) + search-highlight-clearing fix (bug 3) |
docs/handoff.md, docs/progress.md, docs/todos.md, docs/memory-graph-analysis.md, docs/memory-graph-design.md |
updated to reflect M2 done/verified/committed |
Test / verification status
node --checkpasses onstatic/js/memoryGraph.jsafter both fixes.- Full manual browser verification pass completed (see step 8 above) — this is the first real visual confirmation the feature has had; Sessions 1–3 never got past syntax-checking the frontend.
- Backend test suite not re-run this session (only one backend file changed, a two-line owner-variable substitution with no new logic branches; the existing 27 M1 tests don't exercise the no-auth/localhost-bypass code path that the bug lived in, which is exactly how it shipped unnoticed — worth a Milestone 3 follow-up test case for that specific mode).
Session 3 — Milestone 2 (Frontend), stopped mid-verification
Status when stopped: all M2 frontend code written and syntax-checked, but not yet committed and not yet visually verified in a browser. The user interrupted mid-launch to request a documentation-only checkpoint. No further development happened after that instruction — this entry and the other four requested doc files are the only changes made after the stop request.
What was completed this session
- Vendored Cytoscape.js 3.34.0 (MIT license) into
static/lib/cytoscape.min.jsvianpm pack cytoscape@3in a scratch directory, then copied the UMDdist/cytoscape.min.jsbuild — not fetched from a hand-typed/guessed URL, and not installed into the project's ownnode_modules(the app has no bundler; this follows the existing vendoring convention used forxlsx.full.min.js,docx.umd.min.js, etc.). - Wrote
static/js/memoryGraph.js(new file, ~/600 lines) — see full breakdown in "Files changed" below. - Added a "Memory Graph" entry to the sidebar Tools section in
static/index.html, placed directly after the existing "Brain" entry, using the same.list-itemmarkup pattern as every other tool. - Wired it up in
static/app.js:- New static import of
memoryGraph.jsnext to the existingmemory.jsimport. - New click handler block for
#tool-memory-graph-btn, copied from the#tool-calendar-btnblock's exact structure (Modals.toggle(...)check, falling back to the module's ownopenMemoryGraph()/closeMemoryGraph()). - New entry in the
UI_VIS_MAPobject (Customize UI panel) so the nav item can be hidden/shown like any other tool. - New
/memory-graphentry in the_routeOpendeep-link map, mirroring the existing/memoryentry.
- New static import of
- Added one line to
static/js/init.js:hideOn('#tool-memory-graph-btn', privs.can_manage_memory), directly under the existing identical line for#tool-memory-btn, so the privilege gating stays consistent between the two entry points. - Appended a new
/* Memory Graph View (beta) */CSS block to the end ofstatic/style.css(~234 lines) — did not edit any existing rule. - Investigated and fixed a pre-existing, unrelated bug blocking
app.pyfrom importing at all:src/agent_loop.pyuseddict[str, Any]in a function annotation without ever importingAnyfromtyping. Confirmed viagit stashthat this reproduces identically on a cleandevcheckout — not something introduced by this feature. Patched with a one-line import fix so the app could actually be launched for the live demo. This fix is currently uncommitted and its disposition needs the user's explicit decision (seedocs/handoff.md→ Risks). - Started a local server to seed demo data and take a screenshot, using an isolated
ODYSSEUS_DATA_DIR/DATABASE_URL(a scratch directory, not the repo's realdata/) withAUTH_ENABLED=falseandLOCALHOST_BYPASS=truefor frictionless local testing, pointed at the machine's already-running local ChromaDB (localhost:8100) since a completely separate Chroma instance wasn't available. The process was still downloading/loading the FastEmbed embedding model (first-run cache warm-up) when the user's stop instruction arrived. Killed immediately (taskkillon the confirmed PID, verified viaGet-CimInstance Win32_Processthat it was the right process before killing). Nothing was ever seeded — no demo memory entries were created, no port was ever bound, and the isolated data directory (outside the repo, in the session scratchpad) can simply be discarded.
Files changed this session (all uncommitted)
| File | Change |
|---|---|
static/lib/cytoscape.min.js |
new, vendored, 435 KB |
static/js/memoryGraph.js |
new, ~600 lines |
static/index.html |
+17 lines (nav item) |
static/app.js |
+16 lines (import, click handler, UI_VIS_MAP entry, route entry) |
static/js/init.js |
+1 line (privilege gate) |
static/style.css |
+234 lines (appended block only) |
src/agent_loop.py |
+1/-1 line (missing Any import — pre-existing bug, see Risks) |
Test / verification status
node --checkpasses onstatic/js/memoryGraph.js,static/app.js,static/js/init.js(matches the CInode-syntaxjob's check).- No live browser verification performed. No screenshot exists. This is the single most important open item — see
docs/handoff.md. - No new automated tests written for the frontend module this session (not requested as part of M2's explicit requirement list, but flagged as a Milestone 3 item in
docs/todos.md). - Backend (Milestone 1) test status is unchanged from Session 2 (see below) — nothing in Session 3 touched backend code.
Session 2 — Milestone 1 (Backend), completed and committed
What was completed
src/memory_graph.py: purebuild_graph()/build_similarity_edges()/build_session_edges()/build_manual_edges()functions. Similarity edges use one nearest-neighbor query per node againstMemoryVectorStore(never O(n²) pairwise). Manual edges read an additivelinksfield on memory entries.routes/memory/memory_graph_routes.py:GET /api/memory/graph(owner-scoped, filterable by category/min_similarity/max_edges_per_node, with a nodelimit+truncatedflag),GET /api/memory/graph/{id}/neighbors(lazy single-node expansion),POST /api/memory/{id}/linksandDELETE /api/memory/{id}/links/{target_id}(manual relationship editing, gated by the existingcan_manage_memoryprivilege).app.py: mounted the new router beforememory_routes.py's router, with an explanatory comment —memory_routes.py'sGET/PUT/DELETE /api/memory/{memory_id}is a single-segment wildcard that would otherwise swallowGET /api/memory/graph(Starlette matches routes in registration order, not by specificity, across the whole app).- Three new test files:
tests/test_memory_graph_edges.py(14 pure-logic unit tests),tests/test_memory_graph_routes.py(12 route/owner-isolation tests, following the repo's "call the endpoint function directly" convention),tests/test_memory_graph_route_ordering.py(2 tests using a realTestClient— the one place a full ASGI app was needed, specifically to prove the route-ordering fix actually works against real Starlette request matching, which the repo's usual direct-call test style can't verify).
Test status
- All 27 new tests pass.
- Ran the full existing suite (
pytest -q --continue-on-collection-errors) both on this branch and on agit stash-cleandevcheckout in the same throwaway venv. Exact same 199 pre-existing failures/errors on both sides — confirmed viacomm -23/comm -13diff that the sets are byte-for-byte identical. Zero regressions, zero newly-fixed tests (none expected). - All pre-existing failures are sandbox/environment gaps (missing Node.js test runner artifacts for a couple of cases, missing
rgbinary, anmcppackage version newer than the repo pins, Windows-specific path-confinement test assumptions) — none touch memory, graph, or app.py wiring code.
Commits made
5d91d1a docs: add Memory Graph View repository analysis and design
f488a8d feat(memory): add pure edge-derivation logic for Memory Graph View
366bdbf feat(memory): add Memory Graph API — GET /api/memory/graph + manual links
Session 1 — Analysis and design (Phase 0)
- Produced
docs/memory-graph-analysis.md(19-section repo inventory) anddocs/memory-graph-design.md(architecture, API, UI, performance, security, migration/rollback, testing strategy) purely from research — no code touched, no dependencies installed, no database changed, nothing committed at the time (the docs commit itself happened at the start of Session 2, once implementation was approved). - User approved the design and requested implementation with: Cytoscape.js, a dedicated Memory Graph module, automatic semantic relationships, manual relationship editing, a beta feature flag, no breaking changes, small commits, Docker compatibility, passing tests, and incremental delivery with a build/test/preview/approval checkpoint after each milestone.