Skip to content

feat(reject-gate + config): narrow gate, configurable model + reject_pattern via config.json#113

Merged
fdaviddpt merged 3 commits into
mainfrom
fix/reject-gate-narrow-and-configurable
Jun 22, 2026
Merged

feat(reject-gate + config): narrow gate, configurable model + reject_pattern via config.json#113
fdaviddpt merged 3 commits into
mainfrom
fix/reject-gate-narrow-and-configurable

Conversation

@fdaviddpt

@fdaviddpt fdaviddpt commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

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. model is per-project, so config is its natural home.

  • log.sh (sourced by every script, incl. save-session.sh + run-consolidation.sh) bridges config.jsonmodel / reject_pattern to REMEMBER_MODEL / REMEMBER_REJECT_PATTERN. Precedence via ${VAR:=...}: explicit shell env > config.json > built-in default. No Python change — haiku.py already reads these env vars.
  • config.example.json: model + reject_pattern keys with _comments.
  • README: both env rows note config.json is the source of truth.
  • Tests: TestModelConfigBridge sources log.sh and asserts default / from-config / env-overrides-config. 66 passed (test_haiku + test_layered_config).

Also documents REMEMBER_MODEL in the README env table, which #112 added but didn't document.


Context

Follow-up to #112 (merged). The REMEMBER_MODEL knob 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:

output merged #112 this PR
There are no blockers; merged !24648 dropped kept
Unfortunately the build broke; fixed in X dropped kept
It seems the cache was stale; cleared it dropped kept
I notice the staging DB drifted; resynced dropped kept
I cannot invent timestamps. Do you want to: rejected rejected

A visible junk entry is deletable. A silently-dropped real entry is invisible — the worse failure of the two.

Changes

  • 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 removed from the default. All five of feat: configurable model via REMEMBER_MODEL + refusal reject-gate #112's original refusal cases still reject.
  • Add REMEMBER_REJECT_PATTERN env knob (mirrors REMEMBER_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: set REMEMBER_REJECT_PATTERN=none and only the literal SKIP contract applies.

Tests

Added to tests/test_haiku.py:

  • 5 regression guards for the hedged-summary false positives above.
  • _resolve_reject_pattern default / blank-fallback / none-disables / custom / invalid-fallback.
  • gate-disabled keeps a refusal; custom pattern applies.

tests/test_haiku.py: 56 passed. All of #112's original refusal + keep-real-summary cases remain green.

Florian DAVID and others added 3 commits June 22, 2026 09:27
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>
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>
@fdaviddpt fdaviddpt changed the title fix(reject-gate): narrow the default + make it configurable (follow-up to #112) feat(reject-gate + config): narrow gate, configurable model + reject_pattern via config.json Jun 22, 2026
@fdaviddpt fdaviddpt merged commit 8bd6255 into main Jun 22, 2026
12 checks passed
@fdaviddpt fdaviddpt deleted the fix/reject-gate-narrow-and-configurable branch June 22, 2026 07:35
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