Skip to content

Human note-taking voice for the summary family; silence for empty windows - #249

Merged
Ambisphaeric merged 1 commit into
mainfrom
feat/notes-voice
Jul 18, 2026
Merged

Ambisphaeric merged 1 commit into
mainfrom
feat/notes-voice

Conversation

@Ambisphaeric

@Ambisphaeric Ambisphaeric commented Jul 18, 2026 •

Copy link
Copy Markdown
Owner

Closes #245

What

Two quality defects in the distill/summary output, fixed at the prompt-document + engine layer.

1. Notes read like meeting minutes → human note-taking register

Rewrote the SUMMARY-family template bodies in distill/defaults.ts — the distill window note plus all five hierarchical levels (rolling / episode / five-minute / session / project) — from generic "tight, factual summary of what just happened" into a human note-taking register:

  • Lead with the substance ("Feedback to QA — due soon", not "The speaker expressed a goal to provide feedback").
  • Explicitly ban transcription-narration framings ("the speaker said/expressed/stated", "the transcript indicates/shows", "it was mentioned/noted/recorded/discussed", "the notes indicate").
  • Keep the existing invent-nothing honesty rules.
  • Terse: fewest words that carry the fact.

Consistent with the hud-voice surface-language rules. No baked voice dials — the {{tone}}…{{voice.rules}} machinery stays live for user-authored templates. The promptTemplate.distill.json and promptTemplate.summary.json contract examples are updated to the new bodies so their "Mirrors" comments in defaults.ts stay true (byte-verified against the exported defaults).

2. Empty windows still emitted slop → silence over noise

Three complementary drops, all at the distillate (window) seam in distiller.ts:

  • Deterministic pre-gate (DISTILL_MIN_CHARS = 12): a window whose observed material (chunk.data, not capture-lane labels — the fields.ts precedent) is below the floor is dropped without an invoke — no distillate, no moments, no entities. Deliberately LOW (lower than the fast-field gates 40/60/80): the distill note is the primary record, so suppressing a real short utterance ("We ship Thursday.") would be data loss. The floor only catches windows too small for any substantive phrase; the sentinel does the "enough words, no substance" judgment.
  • Model sentinel (NOTHING_NOTEWORTHY, defined in defaults.ts, imported by the distiller): the distill template instructs the model to reply with exactly this token when nothing is worth noting; the engine drops on an exact, case-sensitive, full-text match of the trimmed response. An embedded occurrence in a real note is kept.
  • Empty-response drop: an empty or whitespace-only trimmed response is dropped at the same site — the most literal "nothing", which would otherwise persist as an empty-text distillate.

Downstream verified: the summaries producer already tolerates the resulting gaps. assembleSummaries plans over whatever children exist and buildSummary renders only what it is given, so suppressed windows simply mean fewer/absent children (an all-degraded/empty window degrades honestly rather than fabricating prose).

3. Clobber-safe upgrade

Routed the summary templates through the existing seedOrRefreshBuiltin path and added every rewritten body's prior generation to PREVIOUS_BUILTIN_BODIES. An unedited builtin (version 1 with a byte-identical prior body) auto-upgrades; any user edit (version off 1 and/or divergent body) is never clobbered. PREVIOUS_BUILTIN_BODIES was relocated below the template declarations so its computed keys read initialized consts.

Design notes

  • The sentinel + pre-gate + empty-drop live only at the distillate layer (per issue scope). The hierarchical levels are not sentinel-gated: they ride on already-suppressed distillates, so an empty stretch yields no children and degrades honestly rather than emitting a token the producer would have to special-case.
  • Known upgrade gap: the conservative version === 1 refresh guard means a pre-fix(distill): factory prompt defaults go neutral — strip the baked voice vector from shipped templates #130 install that already auto-refreshed its distill body once (now version 2) will not auto-upgrade to the notes-voice body. Fresh and still-version-1 installs land it automatically. Documented inline.

Tests

  • Template-body assertions: no dial vocabulary, old slop framing dropped, invent-nothing preserved, leads-with-a-note-taking-directive; distill body carries the sentinel and names the banned framings as prohibitions.
  • Suppression units (suppression.test.ts): sub-threshold window → no distillate + no invoke; real short utterance clears the floor; exact/whitespace-trimmed sentinel drops; embedded sentinel kept; empty/whitespace-only response dropped; sentinel-with-trailing-period and lowercase variants kept (strictness is deliberate); a sentinel-dropped window followed by a normal window persists the second normally; dropped window produces no moments/entities.
  • Upgrade tests: unedited summary builtins auto-upgrade; user-edited summary body preserved; existing distill upgrade/conservative tests updated for the new prior body.

Gate (Node 22, rebased onto origin/main @ 605f780)

  • pnpm -r build: clean. pnpm -r test: contracts 114 / fixtures 15 / client 621 / engine 1138, 0 failures.
  • Contracts schema regen (pnpm --filter @openinfo/contracts gen): zero drift (beyond the two intentional example edits).
  • No contract schema changes.

)

Rewrite the summary-family prompt bodies (distill window notes + the five
hierarchical levels) into a human note-taking register: lead with the
substance, ban transcription-narration framings ("The speaker expressed…",
"The transcript indicates…"), keep the invent-nothing honesty rules, stay
terse. Add three silence-over-noise drops so an empty window persists no
distillate: a cheap deterministic pre-gate on observed window material
(DISTILL_MIN_CHARS, deliberately low — the sentinel does the substance
judgment), a model escape that drops the window on an exact
NOTHING_NOTEWORTHY response (embedded token is kept), and an empty/
whitespace-only response drop at the same site. Summary bodies auto-upgrade
for unedited installs via the existing PREVIOUS_BUILTIN_BODIES refresh; user
edits are never clobbered. The distill and summary contract example JSONs are
updated so the "Mirrors" comments stay true.

Closes #245
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.

Notes read like meeting minutes; empty windows still emit slop

1 participant