Discord prefills should pull the whole thread when inside one, per-channel toggle #769

Closed
opened 2026-08-14 03:44:57 +00:00 by coilyco-ops-gaming · 4 comments

Filed on behalf of Kai from Discord.

Discord prefills should always pull in an entire thread when the agent is inside one, not just a partial window.


Resolved spec (design pass, 2026-08-15)

Build

  1. Inside a thread, prefill the whole thread rather than the current partial window.
  2. Gate it on a per-channel setting, default off. Off is the shipped default for every channel, so this lands without waiting on the enablement question below.
  3. Overflow handling, decided by Kai - when the full thread exceeds the context budget, drop oldest messages first until it fits, and say so. The reply annotations must show that the thread was truncated.

Rejected - silent truncation (a wrong answer from missing context would look identical to any other wrong answer), falling back to the partial window (the feature would quietly stop applying in exactly the long threads it was built for), and summarizing the older half (adds a model call and a new failure mode per turn).

Unresolved, and Kai owns it - which channel gets the toggle flipped on. The original filing said "the channel where Kai is seeing this", which no engineer can resolve from the ticket. This does not block the build, because the default is off. Ship the mechanism, then Kai names the channel.

Acceptance

  • In a thread, with the toggle on, the prefill contains every message in the thread up to the budget.
  • With the toggle off, prefill behaviour is byte-identical to today.
  • When truncation happens, the annotation says so and names how many messages were dropped. A test asserts the annotation is present whenever any message was dropped.
  • Outside a thread, nothing changes.
  • Default-off is verified for every configured channel at boot, not assumed.

Context risk - the original concern was overloading ornith. The truncation rule above is what bounds it. Record the observed prefill size on a long thread before flipping the toggle on anywhere.

Related - #750 makes Echo-owned threads permanently summonable with no expiry, which raises the number of turns taken inside threads and therefore the cost of this feature. Land them in either order, and measure prefill size after both.

Filed on behalf of Kai from Discord. Discord prefills should always pull in an entire thread when the agent is inside one, not just a partial window. --- ## Resolved spec (design pass, 2026-08-15) **Build** 1. Inside a thread, prefill the whole thread rather than the current partial window. 2. Gate it on a per-channel setting, default **off**. Off is the shipped default for every channel, so this lands without waiting on the enablement question below. 3. **Overflow handling, decided by Kai** - when the full thread exceeds the context budget, drop oldest messages first until it fits, and say so. The reply annotations must show that the thread was truncated. Rejected - silent truncation (a wrong answer from missing context would look identical to any other wrong answer), falling back to the partial window (the feature would quietly stop applying in exactly the long threads it was built for), and summarizing the older half (adds a model call and a new failure mode per turn). **Unresolved, and Kai owns it** - which channel gets the toggle flipped on. The original filing said "the channel where Kai is seeing this", which no engineer can resolve from the ticket. This does **not** block the build, because the default is off. Ship the mechanism, then Kai names the channel. **Acceptance** * In a thread, with the toggle on, the prefill contains every message in the thread up to the budget. * With the toggle off, prefill behaviour is byte-identical to today. * When truncation happens, the annotation says so and names how many messages were dropped. A test asserts the annotation is present whenever any message was dropped. * Outside a thread, nothing changes. * Default-off is verified for every configured channel at boot, not assumed. **Context risk** - the original concern was overloading ornith. The truncation rule above is what bounds it. Record the observed prefill size on a long thread before flipping the toggle on anywhere. **Related** - #750 makes Echo-owned threads permanently summonable with no expiry, which raises the number of turns taken inside threads and therefore the cost of this feature. Land them in either order, and measure prefill size after both.
Owner

I don't remember asking for a per channel toggle :p

This doesn't seem like a per channel thing, remove that filter condition

I don't remember asking for a per channel toggle :p This doesn't seem like a per channel thing, remove that filter condition
Member

Built. #827 closes this. Angie (ENG, seat claude). All five acceptance criteria, default off everywhere.

Two decisions the spec left to the build

The toggle keys on the parent channel, not the thread. The spec says per-channel and I want the reading on record: threads are created and abandoned constantly, so a per-thread list would be unmaintainable. One entry covers every thread under a channel, which is also what makes "name the channel" a single answer when you get to it.

The annotation is a reply suffix, the same mechanism as the tool receipt, appended after the reply checks and contending for the send budget with the others. It sits ahead of the receipt in the preference order, because the last suffix is the first thing cut and a note about missing context outranks a record of what ran.

A hole in my own first version

The walk is bounded so a pathological thread costs a known number of Discord calls. My first version annotated only when the byte budget dropped something, which means a thread of a thousand short messages that all fit the budget would have been cut by the walk bound and reported as complete. That is exactly the silent truncation you rejected, arriving through a different door.

Fixed: the annotation covers the walk bound too, with its own sentence, and says at least before a length it only knows a floor for. An absent hedge is therefore a claim.

The one thing I cannot give you

Record the observed prefill size on a long thread before flipping the toggle on anywhere.

The span carries history.thread.read and history.thread.dropped, but they only fire when the toggle is on, because measuring a thread's length is the same Discord calls the toggle gates. There is no way to get the number before enabling it somewhere. The first channel you enable is the measurement.

If that ordering matters, the cheap version is enabling one quiet channel, reading the span, and deciding from there. context_prompt_bytes on context.rendered gives today's window size to compare against, and that one is available now.

Still yours

Which channel gets it flipped on. The mechanism is shipped and off, so this is a one-line deployment change whenever you name it.

Also worth knowing before you do: #750 raises the number of turns taken inside threads, so the cost of this rises with it. Measure prefill size after both land rather than after either.

**Built. https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/pulls/827 closes this. Angie (ENG, seat `claude`).** All five acceptance criteria, default off everywhere. ## Two decisions the spec left to the build **The toggle keys on the parent channel, not the thread.** The spec says per-channel and I want the reading on record: threads are created and abandoned constantly, so a per-thread list would be unmaintainable. One entry covers every thread under a channel, which is also what makes "name the channel" a single answer when you get to it. **The annotation is a reply suffix**, the same mechanism as the tool receipt, appended after the reply checks and contending for the send budget with the others. It sits **ahead of the receipt** in the preference order, because the last suffix is the first thing cut and a note about missing context outranks a record of what ran. ## A hole in my own first version The walk is bounded so a pathological thread costs a known number of Discord calls. My first version annotated only when the byte budget dropped something, which means a thread of a thousand short messages that all fit the budget would have been cut by the walk bound and reported as **complete**. That is exactly the silent truncation you rejected, arriving through a different door. Fixed: the annotation covers the walk bound too, with its own sentence, and says `at least` before a length it only knows a floor for. An absent hedge is therefore a claim. ## The one thing I cannot give you > Record the observed prefill size on a long thread before flipping the toggle on anywhere. The span carries `history.thread.read` and `history.thread.dropped`, but they only fire when the toggle is on, because measuring a thread's length is the same Discord calls the toggle gates. **There is no way to get the number before enabling it somewhere.** The first channel you enable is the measurement. If that ordering matters, the cheap version is enabling one quiet channel, reading the span, and deciding from there. `context_prompt_bytes` on `context.rendered` gives today's window size to compare against, and that one is available now. ## Still yours Which channel gets it flipped on. The mechanism is shipped and off, so this is a one-line deployment change whenever you name it. Also worth knowing before you do: https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/750 raises the number of turns taken inside threads, so the cost of this rises with it. Measure prefill size after both land rather than after either.
Member

Toggle gone. #827 updated, 63af061. Angie (ENG, seat claude).

Fair, and the spec is where I got it: the resolved design pass in the body says "gate it on a per-channel setting, default off" and lists which channel to enable as the open question. I built to that rather than to the original filing. Your reading is better and it removes the open question with it: a thread is a bounded conversation someone deliberately opened, so reading it whole is what the feature means, not a per-channel preference.

Removed with it: SIRENS_ECHO_THREAD_PREFILL_CHANNELS, the boot validation for it, the resolved counts I had added to discord.ready, and the three tests that verified a default nobody has any more. Being in a thread is now the entire condition.

What still bounds it, since the switch was doing none of that work anyway

  • The context budget, 32 KiB. Oldest messages drop until the transcript fits, and the reply says how many went.
  • The walk, ten calls of a hundred. A thread longer than that is still annotated, and the annotation says at least before a length it only knows a floor for.

One thing that changed shape rather than going away

The body asks to record the observed prefill size on a long thread before flipping this on anywhere. With no toggle there is no before. It applies from the first threaded turn after rollout.

I do not think that is worse, and I would rather say why than let it pass silently: the numbers land on the community.history span as history.thread.read and history.thread.dropped, so real threads are measured from day one instead of estimated, and any truncation is visible to the member in the same turn. If a long thread does overload ornith, the annotation and the span both say so on the turn it happens rather than after someone notices bad answers.

The one to watch alongside it is still #750, which raises how many turns happen inside threads and therefore how often this runs.

**Toggle gone. https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/pulls/827 updated, `63af061`. Angie (ENG, seat `claude`).** Fair, and the spec is where I got it: the resolved design pass in the body says "gate it on a per-channel setting, default off" and lists which channel to enable as the open question. I built to that rather than to the original filing. Your reading is better and it removes the open question with it: a thread is a bounded conversation someone deliberately opened, so reading it whole is what the feature means, not a per-channel preference. Removed with it: `SIRENS_ECHO_THREAD_PREFILL_CHANNELS`, the boot validation for it, the resolved counts I had added to `discord.ready`, and the three tests that verified a default nobody has any more. Being in a thread is now the entire condition. ## What still bounds it, since the switch was doing none of that work anyway - **The context budget**, 32 KiB. Oldest messages drop until the transcript fits, and the reply says how many went. - **The walk**, ten calls of a hundred. A thread longer than that is still annotated, and the annotation says `at least` before a length it only knows a floor for. ## One thing that changed shape rather than going away The body asks to record the observed prefill size on a long thread **before** flipping this on anywhere. With no toggle there is no before. It applies from the first threaded turn after rollout. I do not think that is worse, and I would rather say why than let it pass silently: the numbers land on the `community.history` span as `history.thread.read` and `history.thread.dropped`, so real threads are measured from day one instead of estimated, and any truncation is visible to the member in the same turn. If a long thread does overload ornith, the annotation and the span both say so on the turn it happens rather than after someone notices bad answers. The one to watch alongside it is still https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/750, which raises how many turns happen inside threads and therefore how often this runs.
Member

Correction, and it needs a second pull request. Angie (ENG, seat claude).

The timing went against me. #827 merged at 17:13 with the toggle still in it, and I pushed the removal at 17:15. So main today ships SIRENS_ECHO_THREAD_PREFILL_CHANNELS with an empty default, which means whole-thread prefill is off everywhere. That is the opposite of what this issue asked for, and my previous comment saying "toggle gone" described a branch rather than main.

Removal is #831, filed as #830 since this one is closed. Nothing else changes: the context budget, the bounded walk, and the truncation annotation are untouched, because those are what hold the cost down and the toggle was doing none of that work.

Worth knowing while 831 is unmerged: the feature is present and inert, so a thread turn today still answers from the partial window.

**Correction, and it needs a second pull request. Angie (ENG, seat `claude`).** The timing went against me. https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/pulls/827 merged at 17:13 with the toggle still in it, and I pushed the removal at 17:15. **So `main` today ships `SIRENS_ECHO_THREAD_PREFILL_CHANNELS` with an empty default, which means whole-thread prefill is off everywhere.** That is the opposite of what this issue asked for, and my previous comment saying "toggle gone" described a branch rather than `main`. Removal is https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/pulls/831, filed as https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/830 since this one is closed. Nothing else changes: the context budget, the bounded walk, and the truncation annotation are untouched, because those are what hold the cost down and the toggle was doing none of that work. Worth knowing while 831 is unmerged: the feature is present and inert, so a thread turn today still answers from the partial window.
Sign in to join this conversation.
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo#769
No description provided.