You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Changed
BREAKING: GET /v1/audit now needs an admin key. A member key used to read its whole tenant's audit log; it now gets 403. Use an admin key; see docs/UPGRADING-2.0.md.
BREAKING: a malformed config.json now stops hippo with the file path and the parse error. It used to log one warning and run on the defaults, which dropped settings such as sharedStore without a trace. Fix the file or delete it; see docs/UPGRADING-2.0.md.
Share, import and sync read text keys, not whole rows.autoShare and the importers call loadEntryTextKeys (now takes an optional tenant) instead of loading every entry of the store.
listMemories reads a page at a time. It returns the same rows in the same order, 1000 rows per query by default; opts.pageSize is new and additive.
Context candidates skip the decay sort under the cap.loadContextCandidates counts the matches first and runs the julianday rank only when more rows match than the cap.
Recall writes go out one statement per 100 rows.strengthenRetrieved updates the retrieval columns with one UPDATE ... FROM per chunk inside the same write scope.
Rejecting a value reads text columns first.applyRejection finds holders from id, content, source, scope and reads whole rows only for the matches.
Incident opens check linked ids in one query per chunk.openIncidentRow no longer runs one SELECT per linked memory; the first unheld link in input order is still the one refused.
The sleep-cycle summary rebuild reads all children in one query per tenant chunk.rebuildDirtySummaries calls loadChildrenOfSummaries once instead of loadChildrenOfSummary per summary; a summary whose child is itself queued is reread so it sees the rebuilt text.
Internal: the reward factor in SQL has one source. rewardFactorSql() in rule-sql.ts builds it for both strengthSql and the context-candidate rank, so a change to REWARD_SLOPE reaches both, and the rank now honours the outcome-slow ablation.
Help text:hippo recall --help and hippo goal --help describe each flag in plain words; the research tracker labels and file pointers are gone. Flag behaviour is unchanged.
Internal: one placeholders(n) helper builds every SQL IN list, one event-log helper serves the GitHub and Slack connectors, the codex-wrapper repair verbs are a column of the verb table, and the dashboard shares round1 and pct with the report code. The strength SQL parity test now covers every emotional valence and a short half-life.
Internal: every caller of the api write functions (remember, rememberLocally, outcome, outcomeForLastRecall, forget, supersede, archiveRaw, authCreate, authCreateSelf, authListRows, authRevoke) and of importVault now awaits the result, so the later async signatures need no caller changes. Behaviour is unchanged.
BREAKING: The api write functions return a Promise on every store.authCreate, authCreateSelf, authListRows, authRevoke, forget, outcome, outcomeForLastRecall, supersede, archiveRaw, remember, rememberLocally and importVault used to return a plain value when the context had no store. They now always return a Promise, and a refusal rejects it instead of throwing. Their generic context parameter <C extends Context> is gone; pass a plain Context. StoreReply and AuthRevokeReply are gone from hippo-memory/server. The last-recall writes move to a new optional lastRecall store group, so outcomeForLastRecall and an outcome with a traceId answer 501 on a store without it. See docs/UPGRADING-2.0.md.
BREAKING: What a store can do now comes from the groups it sets, not from its kind. Three new optional store groups carry the work that used to check kind === 'sqlite': localFiles (the store's hippo.db folder), auditMaintenance (the quality audit, its repairs and audit-log prune) and lessonWrites (git learn). A store without localFiles gets the request fence, 501 on POST /v1/sleep and the other local-only routes, and no auto-sleep. auditMemoryQuality, removeAuditErrors, repairMemoryQuality, repairMemoryQualityOnce, pruneAuditLog and learn now return a Promise and reject with StoreNotPortedError (501) on a store without their group. MCP hippo_learn runs on any store with lessonWrites. remember now returns halfLifeDays and tags, so MCP hippo_remember no longer reads the row back. See docs/UPGRADING-2.0.md.
BREAKING: hippo-memory/server no longer exports withSqliteAllowed, OtherStoreFolderError or __resetSessionRecallHistoryHttp. The reset hooks moved to the new hippo-memory/testing subpath, which is not for production code. The synchronous sqlite store (sqliteSyncStore, storeFor) and finishRecallAt are no longer reachable from a package entry. See docs/UPGRADING-2.0.md, "Server entry and test seams".
BREAKING: the exports a second store needs moved from hippo-memory/server to a new subpath, hippo-memory/store-kit.sqliteStore, hasGroup, StoreBusyError, the HippoStore group and row types, and hippo.db's rule helpers (passesScopeFilterForRecall, encodeVector, rankVectorRows, OTHER_STORE_MARKER and the rest) are now imported from hippo-memory/store-kit. hippo-memory/server keeps serve, the auth functions, the error classes and the *ForCaller hook functions, and still exports the HippoStore type that ServeOpts takes. No name changed. See docs/UPGRADING-2.0.md, "Store kit subpath".
BREAKING: MemoryEntry.tenantId is now tenant_id, and summary_dirty is a boolean. Every other stored field was already snake_case. writeEntry throws a TypeError for an entry that still carries tenantId. CreateMemoryOptions.tenantId is unchanged. hippo export JSON emits the new names; 1.x dormant snapshots are read in both shapes. See docs/UPGRADING-2.0.md.
BREAKING: resolveConflict, writeSessionEndHandoff and the recall loader take options objects, and afterWrite leaves the published write options.loadRecallSearchEntries is replaced at the root by loadRecallEntries(hippoRoot, query, options). hippo decide and hippo predict now reject ids like 12abc and 0x1. docs/UPGRADING-2.0.md lists each change.
Internal: the session-end workflow moved from src/cli/session-hooks.ts to sessionEndWork in src/api/session-end.ts; the CLI passes in its sleep, capture and log steps. The vector codec (float32ToBuffer, bufferToFloat32, still exported, now from hippo-memory/store-kit) moved to src/util/vector-codec.ts, and initializeParticle to src/core/physics.ts. No behaviour changes.
Internal: the LIKE-route switch, the delivery-recorder fault setter and the spool fs setter are gone. The recorder takes fault in its init, the spool functions and runDoctor take an optional fs, and the LIKE branch is reached by a part-word query.
Internal: recall's band ranker, the MCP wide ranker, the CLI ranking core and context now pick physics or hybrid search in one function, searchByEngine in src/search/engine.ts. A golden test pins the ids and order of 23 recalls across the three recall rankers, so the merge moved no ranking.
Internal: the CLI ranking core writes the second store's recall rows through a store named for that root when one is given, the way it writes the first store's rows, instead of always opening hippo.db there.
Tests are deterministic where they were probabilistic. The spool race test now interleaves two replayers through the importer, so it fails on every run of a broken lock instead of by chance. Polling loops and fixed sleeps in the tests use one waitFor helper or a fixed clock, symlink skips narrow to EPERM, and the Linux CI jobs set HIPPO_REQUIRE_SYMLINKS=1 so a missing link privilege fails there instead of skipping. Thirteen copies of the CLI test setup moved to tests/_helpers/cli-env.ts.
Internal: the list-paging test no longer times out on Windows. It seeds its 1003 rows in one transaction without markdown mirrors, since it reads rows only. The boundary case dropped from about 6 s to 0.3 s.
Internal: two tests no longer fail on a slow CI runner. The stream-expiry test now opens the stream with a live key and expires the key afterwards, so a slow runner cannot reach the open after the key has run out. The Slack smoke test now ingests through one connection and states its own time limit, so it no longer times out on Windows.
Fixed
The dashboard no longer writes its access token into the log. A failing /api/ request that carried ?token= now logs the path without its query string.
The cross-encoder reranker now warns when the model loads but every scoring call fails, instead of looking healthy while recall keeps the base order.
A stalled compaction record with unreadable items is logged, and the other stalled records still replay.
A busy or locked database on open no longer turns off full-text search; only a missing fts5 module does.
Resolving a conflict no longer fails when a memory's conflict list is damaged; the other side is still cleaned.
Silent failures now say so. A session worker that cannot queue its request no longer runs unlocked, and a refused queue rename is logged. A reply from the Anthropic API with no text is a failure, not an empty success. Uninstalling hooks reports a settings file it cannot read. A local embedding or judge reply that fails logs a warning once. A memory that could not be indexed for search is logged and reported in the result of a local remember.
A fire-and-forget embed no longer re-embeds the whole store under the embed lock after a model change. It leaves the old index and warns once; hippo embed does the rebuild.
Transport failures are classified by error class and syscall code, not by message text.
The stdio MCP deadline now cancels a call's next step. An aborted request stops before it reads or writes the store; a step already running is not interrupted.
Mirror files are written through a temp file and a rename, so a crash cannot leave a half-written mirror.
Security
BREAKING: the HTTP server and hippo watch start strict, and each default has one explicit opt-out.docs/UPGRADING-2.0.md lists them all.
A keyless request from this machine is a member, so sleep and the quarantine routes answer 403. Opt out with HIPPO_KEYLESS_LOCAL_ROLE=admin.
A non-loopback bind without TLS refuses to start. Opt out with --allow-cleartext or HIPPO_ALLOW_CLEARTEXT=1.
HIPPO_CLIENT_IP_HEADER is read only from the peers in HIPPO_TRUSTED_PROXIES, and boot refuses the header with no proxy listed. * trusts every peer.
Each API key owner gets 20 requests a second, burst 40. Opt out with HIPPO_CALLER_RPS=0.
hippo watch -- <cmd> [args] and runWatched(argv) run with no shell, so no argument is read as shell syntax. --shell and { shell: true } are the opt-in.
hippo dashboard keeps its token off a captured stdout. When stdout is not a terminal, it prints the URL with no token and writes the full URL to .hippo/dashboard.url (mode 0600), replaced at each start.