feat(reject-gate + config): narrow gate, configurable model + reject_pattern via config.json#113
Merged
Merged
Conversation
The reject-gate from #112 marked any output starting with a refusal-like phrase as SKIP so it never reached the memory layer. The intent is right (a model refusal was once stored verbatim as a memory), but the pattern was broad enough to silently drop legitimate hedged summaries: "There are no blockers; merged !24648" -> dropped "Unfortunately the build broke; fixed in X" -> dropped "It seems the cache was stale; cleared it" -> dropped A visible junk entry is deletable; a silently-dropped real entry is invisible. So: - Narrow DEFAULT_REJECT_PATTERN to unambiguous refusal/clarification stems (i cannot/can't/won't/am unable, could you, please provide|paste| share, i'm sorry). The dangerous narrative openers (there are no, it seems|looks like|appears, unfortunately, i notice, bare "sorry") are dropped from the default. - Add REMEMBER_REJECT_PATTERN env knob (mirrors REMEMBER_MODEL / REMEMBER_MAX_TURNS): blank -> default, "none" -> gate disabled, anything else -> custom regex. Invalid regex falls back to the default rather than crashing the backgrounded consolidation run. Tests: regression guards for the 5 hedged-summary false positives, plus default/blank/none/custom/invalid resolution and gate-disabled behavior. All of #112's original refusal cases still reject. 56 passed. Co-Authored-By: fk-nexionlabs <fk-nexionlabs@users.noreply.github.com> Co-Authored-By: Max <noreply>
Co-Authored-By: Max <noreply>
Per request: config.json is the source of truth; env stays as override.
- log.sh (sourced by every script, incl. save-session + run-consolidation)
bridges config.json .model / .reject_pattern to REMEMBER_MODEL /
REMEMBER_REJECT_PATTERN with ${VAR:=...} precedence: explicit shell env
wins, then config.json, then the built-in default. No Python change —
haiku.py already reads these env vars.
- config.example.json: add "model" + "reject_pattern" keys with _comments.
- README: note config.json is the source of truth for both knobs.
- tests: TestModelConfigBridge sources log.sh and asserts default / from-config
/ env-overrides-config for both keys. 66 passed (test_haiku + layered_config).
Co-Authored-By: Max <noreply>
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.
Update — config.json wiring (latest commits)
Beyond the reject-gate narrowing below, both knobs are now surfaced in
config.json(the source of truth), with the env vars kept as overrides — per the "everything in JSON if possible" preference.modelis per-project, so config is its natural home.log.sh(sourced by every script, incl.save-session.sh+run-consolidation.sh) bridgesconfig.json→model/reject_patterntoREMEMBER_MODEL/REMEMBER_REJECT_PATTERN. Precedence via${VAR:=...}: explicit shell env > config.json > built-in default. No Python change —haiku.pyalready reads these env vars.config.example.json:model+reject_patternkeys with_comments.README: both env rows note config.json is the source of truth.TestModelConfigBridgesourceslog.shand asserts default / from-config / env-overrides-config. 66 passed (test_haiku+test_layered_config).Also documents
REMEMBER_MODELin the README env table, which #112 added but didn't document.Context
Follow-up to #112 (merged). The
REMEMBER_MODELknob from that PR is great and untouched here. This corrects one risk in the merged reject-gate: the refusal pattern was broad enough to silently drop legitimate hedged summaries from the memory layer.The intent of the gate is right — a model refusal was once stored verbatim as a memory entry, and that must never reach the memory layer. But the merged pattern also matched normal summary openers:
There are no blockers; merged !24648Unfortunately the build broke; fixed in XIt seems the cache was stale; cleared itI notice the staging DB drifted; resyncedI cannot invent timestamps. Do you want to:A visible junk entry is deletable. A silently-dropped real entry is invisible — the worse failure of the two.
Changes
DEFAULT_REJECT_PATTERNto unambiguous refusal/clarification stems:i cannot|can't|won't|am unable,could you,please provide|paste|share,i'm sorry. The dangerous narrative openers (there are no,it seems|looks like|appears,unfortunately,i notice, baresorry) are removed from the default. All five of feat: configurable model via REMEMBER_MODEL + refusal reject-gate #112's original refusal cases still reject.REMEMBER_REJECT_PATTERNenv knob (mirrorsREMEMBER_MODEL/REMEMBER_MAX_TURNS): blank → narrow default,none→ gate disabled, anything else → custom case-insensitive regex. An invalid custom regex falls back to the default rather than crashing the backgrounded consolidation run.This also keeps the gate's content-judgment opt-out available, addressing the "format validation is the shell's job" intent behind
test_parse_response_headerless_summary/_raw_conversation_echo: setREMEMBER_REJECT_PATTERN=noneand only the literalSKIPcontract applies.Tests
Added to
tests/test_haiku.py:_resolve_reject_patterndefault / blank-fallback /none-disables / custom / invalid-fallback.tests/test_haiku.py: 56 passed. All of #112's original refusal + keep-real-summary cases remain green.