Repository navigation
feat(mental-models): decision-model gate in front of a delta page refresh - #5698
Conversation
80c65a7 to
b8dae31
Compare
|
The zero-kept path bypasses directives, so the claim that directives still apply is only true when at least one memory passes the gate. I reproduced this at exact head Command: Simply always adding current directives would defeat the zero-LLM optimization for banks that have any directive. Could this either track directive freshness and force an edit when a directive changed, or conservatively fall back to the normal path when directives exist and no memory is kept? A regression should also verify that the memory watermark does not make the missed directive permanent. |
…resh A delta refresh reads the memories new since its last run and asks the decision model, one memory at a time, whether it could change the page. Only the kept ones reach the delta LLM call and the reflect loop never runs; none kept means no LLM call, with the watermark still moved past them. Off by default (HINDSIGHT_API_MENTAL_MODEL_REFRESH_DELTA_GATE), and it falls back to reflect when the store can't list memories, the wave is over 200, or the decision model fails. Adds system-eval test_10 (a page already written takes the next wave's update).
- the gated path keeps MemoryFact, not raw dicts; test helpers return dataclasses, not tuples - a failed gated edit reports why (delta_ops_failed), not "empty candidate" - the bank directives reach the gated edit as they do reflect; sibling pages are documented as not offered - one failed decision-model question cancels the rest (TaskGroup) instead of letting them retry - tests: could_change_page, the store read (scope, window, order, limit), the per-bank opt-out, directives, the failed edit - system story test_48: the gate on a real server through the client, with the stub answering it from verdicts - direct-SQL test setup says why; _ScopeWhere moved above its users; no getattr on a known field
- test_48 asserts the whole dry-run result (mode, outcome, preview, applied ops, warnings) - the gate's failure log names the failed question, not the TaskGroup wrapper - ponytail note: the gate's decision-model calls are not in the refresh's usage, like every other decision-model call - delta_updates.py formatted to the 120-column limit
- Drops HINDSIGHT_API_MENTAL_MODEL_REFRESH_DELTA_GATE. Like reflect and consolidation, the gate runs once a decision model is set up; banks opt out with mental_model_refresh_use_decision_model. - Docs: a Knowledge pages paragraph under Decision model; the refresh switch row says what it now covers. - System story runs on the existing decision_model_server; the extra server is gone.
b8dae31 to
c9b8047
Compare
- mental_model_delta_use_decision_model (HINDSIGHT_API_MENTAL_MODEL_DELTA_USE_DECISION_MODEL, default true) turns the gate off for a bank without touching the refresh's reflect, which keeps mental_model_refresh_use_decision_model. - Wired through the bank config API, Python/TypeScript clients, OpenAPI, bank template schema, env templates and docs. - Test: turning off the refresh's switch leaves the gate on.
- Ask whether a decision model exists before loading the bank config. - System story: a bank that opts out of the gate refreshes with reflect. - Unit test: neither the refresh's nor reflect's decision switch turns the gate off. - test_11 on/off compares the gate alone: both runs keep the decision model, off sets MENTAL_MODEL_DELTA_USE_DECISION_MODEL=false. - Re-wrapped docstrings and README lines; the story no longer mentions the removed server.
What
A gate in front of a delta knowledge-page refresh. The refresh reads the memories that are new since its last run. It then asks the decision model, one memory at a time: could this change the page? Only the memories it keeps reach the delta LLM call, and the reflect loop does not run. When none are kept, there is no LLM call at all, and the refresh still moves past those memories.
It is on whenever a decision model is set up, like the decision-model paths for reflect and consolidation. A bank opts out with its own setting,
mental_model_delta_use_decision_model=false(HINDSIGHT_API_MENTAL_MODEL_DELTA_USE_DECISION_MODEL), separate from the refresh's reflect settingmental_model_refresh_use_decision_model. In these cases it falls back to the normal reflect path:It builds on #5382, which is merged.
Why
Decision models are about 1000x cheaper than the LLM. A delta refresh used to pay for a full reflect loop to work out what changed. The gate reads the new memories directly and makes 0 or 1 LLM calls.
Results
The model under test is gemini-3.1-flash-lite, judged by gemini-2.5-flash. The decision model is TypeSafe Jev. There is one run per arm, so treat these numbers as directional.
Cost of one delta refresh (test_05, 20 new memories):
test_01, page convergence: 6/8 without the gate, 7/8 with it. The gate run hit no traps. The run without it hit one,
owner-latest.test_11 (new), a page takes the update: 4/6 without the gate, 6/6 with it. Reflect's search missed "Dana Reyes left the company" and "Kestrel Labs moved to the Team plan", because neither one names the page's topic. The gate judges each memory against the page itself, which does name Dana and Kestrel. How many memories it kept varied by page, from 0 to 51 of 82.
hindsight-decision(our inference API) is not ready for this. It kept 0 of 20 on-topic memories in test_05. In test_01 it scored 5/8 and hit 2 traps.New eval:
test_11_delta_updatesEach case starts with a page that is already written. Then a wave arrives that changes it, mixed with the hard corpus as noise. There are six cases:
Before grading the update, it checks that the wave-1 page stated the old value.
Also in this PR
delta_ops_failed, instead of "empty candidate".test_48_delta_gate. It runs the gate on a real server, with the stub answering the decision model. Only the memory that changes the page reaches the edit, and when none does, there is no LLM call.Not in this PR