Skip to content

fix(hooks): a new session is shown the newest memories; the default briefing level is now minimal - #413

Merged
kevintseng merged 2 commits into
mainfrom
fix/session-start-ranking-ties
Sep 21, 2026
Merged

kevintseng merged 2 commits into
mainfrom
fix/session-start-ranking-ties

Conversation

@kevintseng

@kevintseng kevintseng commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Closes #401.

Two commits, each reviewed on its own:

  1. fix(hooks): a new session is shown the newest memories, not the oldest, when scores tie
  2. feat(briefing): the default briefing level is now minimal

What changes for a user

  • A new session is shown the newest of a group of equally scored memories, not the oldest (SessionStart injects the oldest of a tied group: the hook's ranking has no recency for never-accessed entities and no tie-break #401). The SessionStart hook ranks a project's memories by confidence, use and recency and keeps the top few. Memories captured since the last daily decay carry one confidence value and, never accessed, score exactly alike; SQLite hands equal scores back in ascending id order, so the cut kept the oldest of them. The lesson query, whose pool is claimed first, had no ORDER BY at all and kept the five oldest lessons. Both now resolve newest first (id DESC as the last ORDER BY key of both scored forms, which also serves the global and recent pools that full adds; ORDER BY e.id DESC on the lesson query). A higher score still beats a newer memory.
  • The default briefing level is now minimal (was standard; requested by the maintainer). A new session, and memesh briefing / the briefing tool, gets this project's decisions, lessons, known facts and recent activity, with the live repository state in front of them; the fresh task state and the durable-memory index come back with memesh config set briefing standard or MEMESH_BRIEFING=standard. An explicit setting is honoured exactly as before (env > config > default); an unset or invalid value now resolves to minimal. Only the constant moved; every statement of the old default (source comments, both MCP tool descriptions, AGENTS.md, three READMEs, the skill text, ARCHITECTURE, API_REFERENCE, the dashboard's Project tab in 11 locales, the doc-parity lock) was updated with it, and the tests that assumed the old default were made to say which level they need.

Evidence

Simplification pass

A read-only review of the whole diff looked for anything that could be cut without changing behaviour. Nothing was cut. It found two test-only candidates (about 11 lines) and no source or documentation candidate:

  • tests/core/briefing.test.ts: the tie-parity test restores MEMESH_BRIEFING by hand, although the file's afterEach already calls vi.unstubAllEnvs(); vi.stubEnv would take two lines instead of nine.
  • tests/hooks/session-start.test.ts: a five-line comment above the new describe block repeats the comment on the query it tests.

Neither changes behaviour, and applying them would restart the whole 14-check CI matrix (the Windows legs alone take about half an hour) for a cosmetic gain, so they are left. Kept on purpose, with the reason: the 12-line comment above the query in scripts/hooks/session-start.js (it records a measured SQLite behaviour that nothing else proves); the legacy-form leg of the parity test (nothing else compares the legacy hook's rendered text with the briefing's); the docs/ARCHITECTURE.md bullet (the only reader-facing statement of the tie rule); the two delete isolatedEnv.MEMESH_BRIEFING lines (they follow the existing per-helper pattern, and merging them would refactor code this PR does not own).

Not in this PR (tracked)

…t, when scores tie

The SessionStart hook ranks a project's memories by confidence, use and
recency and keeps the top few. The daily decay multiplies the confidence of
never-accessed memories by 0.9, so the memories captured since its last run
carry one confidence value and, never accessed, score exactly alike (as do
old ones that have sunk to the decay floor), and SQLite returns equal scores
in ascending id order (measured): the cut kept the oldest of them. The
lesson query, whose pool is claimed first, had no ORDER BY at all and kept
the five oldest lessons. On a real graph, in the hours after a decay run, a
new session was given the same two old commit lines every time and never the
decision made an hour earlier, while `memesh briefing` on the same data (a
newest-first window, stable-sorted) showed the right memories.

Add `id DESC` as the last ORDER BY key of both scored query forms (the
schema without scoring columns already ordered by it), which also covers the
global and recent pools that `full` adds, and order the lesson query newest
first. "Newest" is creation order, the key the briefing sorts by too. A
higher score still beats a newer memory.

Tests: a parity test in which every memory ties, lessons included (the hook
byte-equal to the briefing, for both ranking forms); hook tests for a limit
of 3 and for the lesson section; and a control showing that a higher score
still wins, for both forms. Removing the scored tie-breaks turns five of
the new tests red, removing the lesson ordering turns three red, and the
two controls pass either way. docs/ARCHITECTURE.md and the CHANGELOG say
what changed.

Closes #401
The maintainer decided that a new session should get only what belongs to
the project it is in: its decisions, lessons, known facts and recent
activity, with the live repository state in front of them. The fresh task
state and the capped index of durable memories now need `memesh config set
briefing standard` (or MEMESH_BRIEFING=standard). Only the default moved:
the levels, the env > config > default precedence and an explicit setting
are unchanged, and an unset or invalid value now resolves to `minimal`.

The constant in src/core/briefing-level.ts is the one owner of the default
(the hook reads its generated copy). Everything else stated the old default
and moved with it: source comments, the `briefing` and `task_state` MCP tool
descriptions and the OpenAI export copy, AGENTS.md, the three READMEs, the
skill text, ARCHITECTURE and API_REFERENCE, the dashboard's Project tab (all
11 locales) and the doc-parity lock. The CHANGELOG entry says what a new
session no longer gets and how to get it back.

Tests that leaned on the old default now say which level they need (pinned
`standard` where the index or the task state is the subject); new tests
cover the default on the hook, the built CLI and the MCP tool at once. The
live journeys run at `standard`, the level they exercise. The suite's
isolation helpers now drop an ambient MEMESH_BRIEFING, since the tests
assume the default. Setting the constant back to `standard` turns 36 tests
red across four files.

A stale or unknown-age task state still collapses to a one-line flag at
every level, the default included: the `briefing` tool description says so
(the doc-parity lock is re-attested) and the age-unknown flag is now tested
at all three levels.
@kevintseng
kevintseng merged commit 22ffb36 into main Sep 21, 2026
25 of 26 checks passed
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.

SessionStart injects the oldest of a tied group: the hook's ranking has no recency for never-accessed entities and no tie-break

1 participant