Repository navigation
Conversation
When the local vector index isn't ready (every server start until warm-up, a new or empty store, a failed load, GITMEM_SEARCH_MODE=remote), recall called match_gitmem_learnings_weighted. No setup.sql defines it: GIT-93 took the name from nTEG's store. Every customer's cold recall got PGRST202 and returned nothing. - Default prefix: call gitmem_scar_search with similarity_threshold. If the store answers PGRST202 (no such function, e.g. nTEG's), fall back to match_gitmem_learnings_weighted with match_threshold. The first that exists is remembered for the process; any other error is not retried. - Non-default prefix: only match_<table>_weighted. gitmem_scar_search reads gitmem_learnings by name and would search the wrong table. - gitmem_scar_search doesn't return learning_type, applies_when, why_this_matters and the other fields recall renders. They are fetched for the matched ids in one select; if that fails, the rows are returned without them. - Remove the dead semanticSearch (match_gitmem_learnings, no callers). scar-search-rpc-name.test.ts: "tracks the prefix" asserted match_gitmem_learnings_weighted for the default prefix, the bug itself; it now asserts gitmem_scar_search. The semanticSearch test goes with the function. +4 tests: PGRST202 fallback, no retry on a real error, the follow-up select, and tolerating its failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-114) scanRpcNames resolves "/rpc/<name>" in string and template literals (getTableName expanded) and, where the URL is built from a variable, the name properties of the candidate objects in the same file. Fixed https:// URLs (licensing) are classified external. Every store RPC must be defined by setup.sql or allowlisted by ticket; stale entries and unresolved dynamic names fail. Planted-drift self-test included. +5 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ld server (GIT-114) Both must return a seeded scar through the store's RPC. On 1.11.0 the RPC 404s (PGRST202) and both probes find nothing: exit 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
auto-retrieve-hook.sh ran `timeout 2.5 node …`. macOS ships no timeout, the error went to /dev/null, and the hook exited as "nothing relevant", so auto-retrieve never ran on a stock Mac. - quick-retrieve bounds its own run (armDeadline, 2.5 s, unref'd); the hook calls node directly. - Hooks copied into <repo>/.gitmem/hooks looked for a package named "gitmem"; it is gitmem-mcp. The lookup now tries the gitmem-mcp bin, npx's cache (how most installs run it) and the global node_modules. - A missing node or quick-retrieve module is a visible non-blocking hook error (exit 1, reason on stderr), not a silent empty result. The node check runs before prompt extraction, which needed node too. - session-start.sh: debug log per user in $TMPDIR and never fatal under set -e; no pgrep skips the 7 s readiness gate instead of stalling; `which` -> `command -v`; no GNU-only `date +%N`. - resolve-root.sh: pid liveness via kill -0, then /proc (Linux) or ps (macOS), not kill's English error text; host from bash's $HOSTNAME. - credential-guard.sh: the path is JSON-escaped. A quote in it made the block output invalid JSON, which Claude Code treats as allow. test-hooks.sh: +7 portability tests using PATHs with the tool removed (53/53; main fails 6). Unit: +4 (deadline, unref, no timeout call left). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sh depends on it (GIT-116) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…GIT-117) syncThreadsToSupabase called create/resolve/touch helpers that caught their own failures and returned null/false/void, which the loop never read. So a thread whose write the store rejected was counted as synced: session_close reported COMPLETE, pruned threads.json and deleted the session files, and a local-only thread was dropped as stale 24 h later. - The loop uses throwing variants: a create counts when directUpsert returns the row; a resolve or touch counts only when the PATCH returns a row (0 rows = failed); a thread the store doesn't have is a failure, not a no-op. touchThreadsInSupabase reports per-thread outcomes. - Partial sync: the close says PARTIAL (session saved, threads not) and names the failed ids; threads.json keeps them marked sync_pending. - session_start keeps sync_pending threads whatever their age and prefers their local state over the store's (so an unwritten resolution survives) until a later close writes them; a full sync clears the flag. thread-sync-result.test.ts: the GIT-70 tests only failed the lookup, the one call that propagated. +6 tests fail the writes; 5 fail on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ks PARTIAL + carry-forward (GIT-117) On 1.11.0 the store rejects the thread and the close says COMPLETE with no pending marker: exit 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…q (GIT-116) macos-latest (macOS 15) has /usr/bin/jq as a system tool, so asserting its absence failed the job. The jq-less path stays covered by hooks-without-jq on Linux; the macOS leg now reports whether stock jq is present. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s (GIT-118) loadScarsFromSupabase returned [] on any error with no flag. flushCache (fired after every create_learning, and every 15 min) reinitialised the index and overwrote hook-scars.json with it, logged "N -> 0", and reported success. A failed init was cached as ensureInitialized's promise, so it was never retried. - loadScarsFromSupabase reports ok/error; on failure it offers the last disk vector cache (stale) instead of [], and never as "the store is empty". - A failed reload keeps the index and the hook cache (an empty index takes the stale disk copy) and returns success: false with the cause. - A failed load retries with backoff (30 s, doubling, 10 min cap); ensureInitialized forgets a failed init; an init after a stale start replaces the stale rows (initialize() is a no-op once initialized). - create_learning awaits a refresh and its display says when the recall index could not be refreshed (index_refreshed: false). The post-write refresh uses the per-row delta (GIT-98), not the disk-bypassing flush. +7 startup tests (6 fail on main), +2 create_learning display tests. Three test files mocked startup.js without refreshIndexAfterWrite; the missing export threw inside create_learning's try and every call reported "NOT refreshed" unseen. Their mocks now provide it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…all survives (GIT-118) A forwarding proxy in front of the venue fails GET gitmem_learnings* on demand while writes pass. On 1.11.0: "Flushed and reloaded: 5 -> 0", create_learning silent, recall empty; exit 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… not durable (GIT-119)
archive_learning sent id=like.<prefix>% against a uuid column, which Postgres
rejects (42883), so prefix archiving failed on every store. The prefix now
resolves from the local index, or from the store as a UUID range when cold.
directPatch returns { count, rows }. PostgREST answers 200 [] when a PATCH
matched nothing; all 8 callers now treat count 0 as not durable (archive of a
nonexistent id, session embedding, superseded mark, thread resolve/touch/
auto-archive, relevance update, transcript path).
Tests: +12 (9 parameterized zero-row cases, 3 archive). Venue driver gains a
prefix archive of a row the index has not seen, and a nonexistent full UUID.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ooks (GIT-120) install-hooks replaced settings.hooks wholesale and uninstall-hooks deleted the key, so users' own hooks were lost. Both now work per event and per command: only commands gitmem installed are replaced or removed, a matcher group keeps its other commands, events install-hooks does not manage stay untouched, the file is backed up before every write, and the output lists what changed. An unparseable file is no longer overwritten "fresh". gitmem detection matches gitmem's script paths instead of any "gitmem" substring, which made a foreign hook under a gitmem-named directory look like an existing install. Tests: new CLI e2e (9) with foreign hooks present, wired into CI. Two cli-fresh-install assertions that pinned the old wipe are updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # tests/e2e/blank-supabase.mjs
# Conflicts: # tests/e2e/blank-supabase.mjs
# Conflicts: # src/services/thread-supabase.ts
…stack)
GIT-117's tests mocked directPatch as an array. After GIT-119 it returns
{ count, rows }; with the old mock a 0-row PATCH read as success.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ig + hooks (GIT-115) init seeded <cwd>/.gitmem while the server reads ~/.gitmem (GIT-91), so a fresh install had no starter lessons and was told its store was "NOT being read". The wizard and init-scars now seed learnings, threads, collections and the closing payload + template into the root the server reads (GITMEM_DIR, then GITMEM_HOME/.gitmem, then ~/.gitmem). The repo's .gitmem/ keeps only config.json (project name) and the hook scripts. - A repo .gitmem/ with only config.json and hooks, or only what an older init seeded, is not a stranded store. Real records (a user's learning, thread or decision) now count, which main did not check at all. - The SessionStart hook reads the repo's project name without jq (node). - uninstall removes the repo's config.json and hooks; the shared store is kept unless --all or the user says delete. Hook removal and the wizard's hook merge use the GIT-120 module (bin/hooks-merge.js, identical to #55). - telemetry commands use the server's root. Tests: fresh-install e2e in a clean HOME (9, all fail on main), unit +5, hook suite +1. cli-fresh-install made hermetic (scratch HOME) and repaired; both e2e files wired into CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # .github/workflows/ci.yml # bin/gitmem.js
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CHANGELOG [Unreleased] -> [1.11.1] - 2026-09-22, fresh [Unreleased] above. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release D (GIT-113 Phase 1): all seven items stacked. Chris decides the release.
Just upgrade the package. Nothing to change on your database.
schema/andsupabase/are unchanged from main.No version bump, tag, merge or publish. The CHANGELOG entry is under
[Unreleased].Stacked
gitmem_scar_search. The drift analyzer now covers RPC names.timeout. The prompt-hook time limit moved into quick-retrieve. macOS CI leg added.archive_learningresolves prefixes by UUID range. All 8directPatchcallers treat 0 rows as not durable.config.jsonand hooks (Chris's ruling). The wizard and uninstall use GIT-120 matching.Stack integration
tests/e2e/blank-supabase.mjsconflicted at GIT-117 and GIT-118 merges. Every probe and check from both sides was kept.src/services/thread-supabase.tsconflicted between GIT-117 and GIT-119. GIT-117'sresolveThreadRowwas kept, and its row checks now readpatched.count.bin/gitmem.jsimports and the CI e2e steps. Both sides were kept.bin/hooks-merge.jsis identical on fix: install/uninstall-hooks merge per event, keep foreign hooks (GIT-120) #55 and fix: init seeds the store the server reads; repo keeps config + hooks (GIT-115) #57.{count, rows}shape. With the old array mock, a 0-row PATCH read as success.Gate results (release/D @ 0624096, rerun after adding GIT-115)
timeout), scratch HOMEEXPECTED_FAILURESEvery item's probe passes in both venue flows: remote recall, cold recall, thread-sync PARTIAL, reload failure, archive by prefix, and archive of a nonexistent id. The only non-2xx responses are the two designed probes for production-only optional columns (
task_observations,archived_at).Hook suites ran with a scratch HOME. With the real HOME on the dev machine, two "not detected" tests fail on every branch because the user-level Claude config registers gitmem. CI runners have no such file.
Venue: the disposable
vujndhcumgroztfkkdus, left on v1.8.0. A first local attempt failed before any test ran, because PostgREST's schema cache was stale after the reset. The local script now sends the sameNOTIFY pgrstthe CI script sends, and the whole sequence was rerun from the v1.8.0 reset.🤖 Generated with Claude Code