Skip to content

Release B: honest health, usage recorded, no writes to columns the store lacks (GIT-84/104/106/108/109) - #36

Merged
nTEG-dev merged 15 commits into
mainfrom
release/B
Sep 21, 2026
Merged

nTEG-dev merged 15 commits into
mainfrom
release/B

Conversation

@nTEG-dev

Copy link
Copy Markdown
Member

Release B: prepared for release. Chris decides the merge and tag. No version is set; the CHANGELOG draft is under [Unreleased].

⚠️ nTEG's own upgrade requires a privately held migration (scar_usage → orchestra_scar_usage, kept in the private orchestra repo). Customer stores need nothing.

Contents

Change
#32 · GIT-104 health counts {success:false} results and swallowed errors as failures
#33 · GIT-84 The usage table goes through getTableName, setup.sql can be re-run, the scoring function only rewrites changed rows, and a table-name guard test is added. The nTEG-only migration is removed from the package.
GIT-106 A/B variants are dev-tier only. All 3 paths consult hasVariants(): assignment in recall, generation in create_learning (which wasn't gated before), and the variant_performance_metrics write.
GIT-108 Analytics no longer selects scar_title/scar_severity. They're filled from learnings by the existing enrichScarUsageTitles(), which every caller already runs.
GIT-109 Applied memories and relevance ratings go into gitmem_query_metrics.metadata, with no new column. Recall rows carry the session in metadata.session_id so the relevance update can find them. hook-scars.json is now 0600.
Store-aware writes Required by the overriding rule. These are pre-existing defects in 1.8.0 and 1.9.0, found by auditing every write against the v1.8.0 schema:
• session_close sent task_observations, children and claude_code_session_id, which are production-only columns. Reproduced on 1.9.0 against a 1.8.0 schema: the whole close got a 400 and the session was lost.
• absorb_observations writes task_observations.
• archive_learning writes archived_at, which rejected the whole PATCH, so the scar was never archived.
• Transcript upload targets a bucket and a transcript_chunks table that setup.sql doesn't create.
The tier can't tell nTEG's store from a customer's (nTEG validates as pro), so store-columns.ts asks the store: a read-only one-row SELECT, cached per process. Optional columns are written only where they exist.

Gates (all on release/B)

Gate Result
a. npm ci --legacy-peer-deps, tsc, unit suite with an isolated HOME ✅ vitest 4.0.18 · tsc clean · 84 files / 1274 tests (1.9.0: 76 / 1234)
b. Old schema: venue reset and provisioned from v1.8.0 setup.sql, then the script run on release/B ✅ exit 0. The close persisted; gitmem_scar_usage got 1 row; relevance is readable (memories_applied, memory_relevance: high). 0 missing-column errors. 0 /functions/v1/ requests; threads 3 = 3. health: only GIT-73 and GIT-105.
c. New schema: release/B setup.sql applied on top, then applied again ✅ Both applications succeeded. Script exit 0: usage row landed, relevance readable, close persisted. health: only GIT-105 (GIT-73 is intermittent).

The script's EXPECTED_FAILURES is now GIT-73 and GIT-105 only. The capability probe's designed 400 (GET gitmem_sessions?select=task_observations&limit=1) is reported separately as capability_probes, matched on exact shape; it's a read, not a defect.

Baseline for comparison: the same script on 1.9.0 against the 1.8.0 schema exits 1. The close is lost (POST gitmem_sessions → 400, PGRST204 task_observations), and relevance isn't readable.

Tests added

Answers

  • Do variants work on nTEG's store? No, not after this release: nTEG's license validates as pro, and variants are now dev-only. Before this release they ran there against unprefixed tables; see the rehearsal report for whether those exist in production.

No merge, no tag, no publish.

🤖 Generated with Claude Code

Claude and others added 13 commits September 20, 2026 20:29
…er (GIT-104)

track() recorded any resolved promise as a success. Several tracked writers
catch their own errors and resolve anyway, so `health` reported failed writes
as succeeded. On a blank Supabase, scar_usage 404s and knowledge_triples 400s
were both counted as successes.

- track(): a resolved value of the form { success: false } is recorded as a
  failure (message from error, then message, then display). The value is still
  returned to the caller. Rejections are unchanged.
- Tracked writers that swallowed errors now let the tracker see them:
  - writeTriples attempts every triple, then rejects with a summary if any
    failed.
  - generateVariantsForScar rejects if a variant insert failed.
  - Cache writes under track() use a rejecting writeResult(). setResult()
    keeps swallowing for its direct callers.
  - The session_close transcript task returns the save result.
- recordScarUsageBatch reports the error text on failure.

Tests: +11 (6 effect-tracker outcome accounting, 5 tracked-writer failure
surfacing).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…-applicable (GIT-84)

Scar usage was written to and read from the literal table "scar_usage". That
table does not exist on a customer store (setup.sql creates gitmem_scar_usage),
so every usage write 404'd and the loss went unnoticed. On a blank Supabase,
gitmem_scar_usage stayed at 0 rows after recall, confirm_scars and
session_close.

- record-scar-usage, record-scar-usage-batch, analytics and behavioral-decay now
  use getTableName("scar_usage"). The two storage.upsert("scar_usage") sites are
  unchanged: the storage layer already applies the prefix.
- Guard test: fails on a bare table-name literal passed to directUpsert,
  directQuery, directQueryAll or directPatch, in a `table:` option, or in a
  REST URL. It also fails if storage is handed an already-prefixed name.
  Literals that setup.sql creates under exactly that name are allowlisted
  pending a ruling.
- setup.sql:
  - refresh_scar_behavioral_scores() only rewrites rows whose decay_multiplier
    actually changes. Otherwise, once usage rows land, it bumps updated_at on
    every session_start and invalidates the GIT-98 disk cache.
  - Adds the missing DROP POLICY IF EXISTS for gitmem_licenses and
    gitmem_license_activations, so a second run no longer fails at statement 72.
- schema/migrations/GIT-84-ntegs-scar-usage-rename.sql: NOT EXECUTED. Needs
  human review. nTEG's install (prefix orchestra_) keeps usage in plain
  scar_usage; this renames it to orchestra_scar_usage and leaves a
  security_invoker compatibility view.

Tests: +8 (4 table-name guard, 4 setup.sql re-apply safety).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…age (GIT-84)

schema/ ships in the npm package, so the nTEG-specific rename migration would
have gone to every customer. It now lives in the private orchestra repo
(ops/migrations/). nTEG's own upgrade still needs that privately held
migration before it runs this release.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
setup.sql doesn't provision what the variant paths need:
- scar_enforcement_variants has no `active` column
- variant_assignments and variant_performance_metrics don't exist

So on a customer (pro) store every variant read and write failed.

- hasVariants() is now dev-only.
- Variant generation in create_learning now consults hasVariants(). Before,
  it ran on every scar on any Supabase tier.
- The variant_performance_metrics write in recall states its hasVariants()
  gate explicitly. It was already nested inside that block.

Tests: +7 (the predicate on free, pro and dev; recall assignment and the
metrics write skipped on pro and run on dev; create_learning generation skipped
on pro and run on dev). The two create_learning test tier mocks gain
hasVariants.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…T-108)

gitmem_scar_usage has never had those columns, so the analytics, session_start
insight and session_close blindspot reads failed with 400 "column does not
exist" once GIT-84 pointed them at the real table.

The query now selects only scar_id, agent, reference_type,
execution_successful and surfaced_at, and returns title and severity as null.
The existing enrichScarUsageTitles() fills them from the learnings table by id;
every caller already runs it.

Tests: +2. The select is checked against the columns setup.sql actually
creates, and enrichment fills title and severity from learnings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ache owner-only (GIT-109)

updateRelevanceData upserted a memories_applied column that
gitmem_query_metrics has never had, and matched free-text Q6 titles against
UUIDs, so no relevance was ever recorded. The upsert also omitted tool_name
(NOT NULL), so it could not have succeeded anyway.

- updateRelevanceData PATCHes the existing metric row and merges
  metadata.memories_applied (UUIDs) and metadata.memory_relevance
  ({uuid: high|low|noise}) into the metadata JSONB every schema since 1.8.0
  has. Existing metadata keys are preserved.
- hook-scars.json holds learning text and was world-readable (0644). It is
  now written 0600 and chmod'ed, which also tightens files from earlier
  installs, matching the vector disk cache.

session_close's new input (APPLYING confirmations plus ratings) is wired in
the next commit.

Tests: +4

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…s on setup.sql stores

Customers often upgrade the package without re-running setup.sql. Several
paths wrote objects that setup.sql never creates. PostgREST rejects the whole
write on one unknown column, so:

- session_close sent task_observations, children and claude_code_session_id,
  which exist only on nTEG's store. On a blank Supabase with 1.9.0, a
  CLI/desktop close that found a Claude Code transcript, or carried
  observations, got a 400 and the session was lost (close reported FAILED).
- absorb_observations upserted sessions.task_observations and failed every
  time.
- archive_learning PATCHed learnings.archived_at, so the learning was never
  archived.
- transcript capture uploaded to a session-transcripts bucket and wrote
  gitmem_transcript_chunks, neither of which setup.sql creates.

The tier can't tell a customer store from nTEG's (both validate as pro), so
the store is asked. store-columns.ts runs a read-only one-row SELECT of the
named columns, cached per process. An inconclusive probe is treated as absent:
skipping an optional field is safe, sending one is not.

- filterToStoreSessionColumns drops production-only session columns this
  store lacks.
- absorb_observations, archive_learning and transcript capture check before
  writing.
- nTEG's store keeps every field it has today.

Also wires GIT-109 into session_close. APPLYING confirm_scars decisions and
their relevance ratings feed updateRelevanceData. Q6 entries count only when
they name a surfaced scar by UUID or exact title.

Tests: +8 store-columns. Three tool suites that model nTEG's store now mock the
probe as "present", and the session_close mock gains getConfirmations.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t; checks the close landed and relevance is readable

- flow now calls absorb_observations and plants a Claude Code transcript where
  session_close looks for one. That's the path every real CLI/desktop close
  takes, and on 1.9.0 it lost the close on a setup.sql store.
- The run fails unless:
  - the session row is persisted with its closing_reflection
  - (when recall surfaced scars) gitmem_query_metrics.metadata carries the
    confirmed scar in memories_applied and memory_relevance (GIT-109)
- EXPECTED_FAILURES shrinks to GIT-73 and GIT-105. The GIT-84 (scar_usage
  404) and GIT-106 (variants 400) entries are removed now that both are fixed
  in this release.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ally recorded (GIT-109)

recall wrote its metrics row with session_id NULL, so updateRelevanceData,
which looked rows up by session_id, only found session_start and
session_close. Neither surfaces memories, so nothing was ever patched, while
relevance_update still reported success.

recall now records the session in metadata.session_id. It doesn't use the
session_id column, because that column's FK would race the session row's
creation (the GIT-73 race). updateRelevanceData matches either place.

Verified on a blank Supabase provisioned from the v1.8.0 setup.sql: after
recall, confirm_scars (APPLYING, relevance high) and session_close, the recall
row's metadata carries memories_applied and memory_relevance.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…reads relevance where recall stores it

- Capability probes are reported, not failed: a read-only GET
  ?select=<optional columns>&limit=1 (or select=id on a transcript_chunks
  table) that 400s or 404s is how gitmem learns a column or table is absent.
  They're matched on exact shape only. EXPECTED_FAILURES, the defect list, is
  unchanged at GIT-73 and GIT-105.
- The relevance check reads metrics by session_id or metadata->>session_id,
  matching where recall records it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@nTEG-dev

Copy link
Copy Markdown
Member Author

GIT-84 migration rehearsal (nTEG's private upgrade step). This was run on the disposable gitmem-e2e project, never on production.

  • The production shape of scar_usage was rebuilt from orchestra's supabase/migrations: columns, the updated_at trigger, 3 RLS policies, grants, 6 FKs including scar_violations → scar_usage, the scar_usage_lite view, and production's refresh_scar_behavioral_scores(). It comes from the repo, not the live catalog, because no read-only path to production's catalog was available in-session.
  • After the migration, everything passed through PostgREST. The old name, read through the compatibility view, gave 200. A 1.9.0-style merge-duplicates INSERT gave 201, and an UPSERT on an existing id gave 200 with the row updated. A CODA-1 INSERT gave 201 and its PATCH gave 200, with the trigger firing. scar_usage_lite gave 200, the scar_violations FK insert 201, new-name reads and upserts 200/201/200, and the refresh RPC 200, reading through the view.
  • The rollback restored the original catalog state, and rows written while migrated persisted. The venue was cleaned up afterwards.
  • Production's refresh function already updates only rows whose score changed (ABS(...) > 0.01), so nTEG doesn't need this PR's setup.sql scoring change.
  • Before running the migration, run the read-only inventory: ops/migrations/GIT-84-inventory.sql on orchestra branch ops/GIT-84-scar-usage-rename-migration. It confirms the dependents against the live catalog, and also shows whether the variant tables (GIT-106) and the optional session and learning columns exist in production.

Claude and others added 2 commits September 20, 2026 22:05
Release B:
- GIT-110: session closes no longer lost on customer stores
- GIT-84: scar usage recorded; setup.sql re-runnable
- GIT-104: health reports hidden failures
- GIT-106: variants dev-only
- GIT-108: analytics columns
- GIT-109: relevance saved in metadata; hook cache 0600

Re-running setup.sql is recommended but not required.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@nTEG-dev

Copy link
Copy Markdown
Member Author

Final prep: 3c61aa0 (v1.10.0)

  • Version 1.10.0. The CHANGELOG [1.10.0] - 2026-09-21 entry opens with the GIT-110 session-loss fix, then the setup.sql advice, then the health note.
  • Unit suite: after npm ci --legacy-peer-deps with vitest 4.0.18, tsc is clean and 84 files / 1274 tests pass.
  • Test script on 31fff6f (3c61aa0 changes only the CHANGELOG date): exit 0 against the v1.8.0 schema, and exit 0 against this release's setup.sql, applied twice with both applications succeeding. Each run saved the close, recorded usage, and had readable relevance. health showed only GIT-73 and GIT-105.
  • Pack: 250 files, against 248 in 1.9.0. Added: dist/services/store-columns.{js,d.ts}. Nothing removed. schema/ has only setup.sql and starter-scars.json.
  • nTEG's own installs are pinned to gitmem-mcp@1.9.0 (desktop, .mcp.json, and the global CLI, which no longer runs from a development folder) until production's scar_usage migration runs.

@nTEG-dev
nTEG-dev marked this pull request as ready for review September 21, 2026 05:11
@nTEG-dev
nTEG-dev merged commit b1b3cb9 into main Sep 21, 2026
4 checks passed
@nTEG-dev
nTEG-dev deleted the release/B branch September 23, 2026 05:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant