When a request triggers the 4 second intial intial draft response - we should add a 6 second artificial delay so that the next edit doesn't come in immediately #272

Closed
opened 2026-08-13 05:27:20 +00:00 by coilysiren · 7 comments
Owner

observed behavior:

  • The response time is known to take 4.1s overall
  • The pending reply feature kicks in at 4s
  • +0.1s the response comes in and fills in the message, and basically always the response is large, so it churns the channel

desired behavior:

  • The response time is known to take 4.1s overall
  • The pending reply feature kicks in at 4s
  • artificial delay kicks in for 6s (after the 4s), concurrently the response comes in @ +0.1s so 4.1s BUT it does not get posted
  • at 10s, the reply gets posted
observed behavior: - The response time is known to take 4.1s overall - The pending reply feature kicks in at 4s - +0.1s the response comes in and fills in the message, and basically always the response is large, so it churns the channel desired behavior: - The response time is known to take 4.1s overall - The pending reply feature kicks in at 4s - artificial delay kicks in for 6s (after the 4s), concurrently the response comes in @ +0.1s so 4.1s BUT it does not get posted - at 10s, the reply gets posted
Member

Grounding the numbers, since this is a small change and the constants just moved — Quail (QA).

Current state on main (internal/community/turnprogress.go):

turnProgressAfter = 4 * time.Second   // first draft posts
turnProgressEvery = 2 * time.Second   // every edit after that

04009dc set both an hour ago, at your request, and pinned them with a test asserting the constants rather than only their effect.

So the ask reads as: keep turnProgressAfter at 4s, raise the gap before the first edit to 6s, leaving later edits at 2s. That is a different shape from either constant — it is a one-off delay between the initial post and the first edit, not a change to the steady cadence.

Two ways to read it, and they behave differently:

  1. First edit at 10s (4s post + 6s), then every 2s after. The draft has visible dwell time before it starts changing.
  2. turnProgressEvery → 6s across the board. Simpler, but it also slows every later edit, which undoes half of what 04009dc just did.

I read the title as (1) — "the next edit doesn't come in immediately" is about the first transition specifically. Worth confirming before someone implements (2), because the constant is right there and it is the tempting change.

One thing to check while implementing. turnProgressAfter is 4s and the turn deadline is 180s, but the model-stage failures measured in #190 mean a meaningful share of turns never reach a reply at all. A longer first-edit gap means a failing turn shows a stale draft for longer before the failure notice replaces it. Probably fine at 6s; worth knowing the interaction exists rather than discovering it.

No verdict from me — this is a product tempo decision, and the numbers above are so it can be specified against what is actually there. Whoever takes it should extend the existing constant test rather than adding a new one, since 04009dc already established that pattern.

**Grounding the numbers, since this is a small change and the constants just moved — Quail (QA).** Current state on `main` (`internal/community/turnprogress.go`): ```go turnProgressAfter = 4 * time.Second // first draft posts turnProgressEvery = 2 * time.Second // every edit after that ``` `04009dc` set both an hour ago, at your request, and pinned them with a test asserting the constants rather than only their effect. So the ask reads as: **keep `turnProgressAfter` at 4s, raise the gap before the *first edit* to 6s**, leaving later edits at 2s. That is a different shape from either constant — it is a one-off delay between the initial post and the first edit, not a change to the steady cadence. Two ways to read it, and they behave differently: 1. **First edit at 10s** (4s post + 6s), then every 2s after. The draft has visible dwell time before it starts changing. 2. **`turnProgressEvery` → 6s** across the board. Simpler, but it also slows every later edit, which undoes half of what `04009dc` just did. I read the title as (1) — *"the next edit doesn't come in immediately"* is about the first transition specifically. Worth confirming before someone implements (2), because the constant is right there and it is the tempting change. **One thing to check while implementing.** `turnProgressAfter` is 4s and the turn deadline is 180s, but the model-stage failures measured in https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/190 mean a meaningful share of turns never reach a reply at all. A longer first-edit gap means a failing turn shows a stale draft for longer before the failure notice replaces it. Probably fine at 6s; worth knowing the interaction exists rather than discovering it. No verdict from me — this is a product tempo decision, and the numbers above are so it can be specified against what is actually there. Whoever takes it should extend the existing constant test rather than adding a new one, since `04009dc` already established that pattern.
Member

DELIVERED — Angie (ENG). Landed as 12c4e49. Your timing, implemented as specified.

Your scenario, now:

moment before now
4.0s line posts line posts
4.1s model returns, reply replaces the line immediately model returns, reply is held
10.0s reply posts

There is a test using exactly your numbers: a line posted at the 4 second threshold, the model returning 0.1 seconds later, and the hold coming out at the window minus that tenth of a second.

Three bounds on the cost, each with its own test, because an artificial delay is easy to make worse than the churn it fixes:

  • A turn that never posted a line is never held. This is the important one. An ordinary fast reply is completely unaffected, so the delay only applies to turns that were already slow enough to narrate.
  • A line already visible longer than the window is not held again. A genuinely long turn, the 180 second ones from the outage, does not pay the delay on top of everything else.
  • A cancelled turn stops waiting rather than sitting on the member's answer for the full window.

The failure path holds too. A notice replacing a just-posted line churns exactly as much as a reply does, and it would have been an odd asymmetry to fix one and not the other. It reaches the progress line through the turn context rather than taking a new argument, the same route the tool round and the reactions already use.

One consequence worth stating plainly rather than leaving you to notice it. Every narrated turn is now at least 10 seconds end to end. That is the intended trade, but it is a real one: a turn that would have answered at 4.1 seconds now answers at 10, and the member waits longer for the same answer. If that reads badly in practice, the window is one constant and I would rather tune it on your observation than guess now.

ward exec build, policy-check, vet, test, and the full pre-commit gate pass. Not deployed. Rollout rides coilyco-bridge/deploy#427, and this is the third progress change queued behind it, with the 4s/2s cadence and the sink telemetry.

Closing. Worth re-checking against a real channel once it rolls, since the whole point is how it reads rather than what the clock says.

**DELIVERED — Angie (ENG).** Landed as `12c4e49`. Your timing, implemented as specified. Your scenario, now: | moment | before | now | | --- | --- | --- | | 4.0s | line posts | line posts | | 4.1s | model returns, **reply replaces the line immediately** | model returns, reply is held | | 10.0s | — | reply posts | There is a test using exactly your numbers: a line posted at the 4 second threshold, the model returning 0.1 seconds later, and the hold coming out at the window minus that tenth of a second. **Three bounds on the cost, each with its own test**, because an artificial delay is easy to make worse than the churn it fixes: - **A turn that never posted a line is never held.** This is the important one. An ordinary fast reply is completely unaffected, so the delay only applies to turns that were already slow enough to narrate. - **A line already visible longer than the window is not held again.** A genuinely long turn, the 180 second ones from the outage, does not pay the delay on top of everything else. - **A cancelled turn stops waiting** rather than sitting on the member's answer for the full window. **The failure path holds too.** A notice replacing a just-posted line churns exactly as much as a reply does, and it would have been an odd asymmetry to fix one and not the other. It reaches the progress line through the turn context rather than taking a new argument, the same route the tool round and the reactions already use. **One consequence worth stating plainly rather than leaving you to notice it.** Every narrated turn is now at least 10 seconds end to end. That is the intended trade, but it is a real one: a turn that would have answered at 4.1 seconds now answers at 10, and the member waits longer for the same answer. If that reads badly in practice, the window is one constant and I would rather tune it on your observation than guess now. `ward exec build`, `policy-check`, `vet`, `test`, and the full pre-commit gate pass. Not deployed. Rollout rides https://forgejo.coilysiren.me/coilyco-bridge/deploy/issues/427, and this is the third progress change queued behind it, with the 4s/2s cadence and the sink telemetry. Closing. Worth re-checking against a real channel once it rolls, since the whole point is how it reads rather than what the clock says.
Author
Owner

Ah I see... okay lets adjust the numbers and collapse concepts.

turn progress start message draft thing gets posted @ 3 seconds of wait time

after that point, the agent starts sending back its responses whenever... BUT

if first edit / final response doesn't come in by 3.1s, it hits the +6s artificial delay, so it wont show up until 9s

if the response isn't done by 9s, it hits another artificial delay. so 9.1s won't come in immediately either, it has to wait until 15s

and so on...

Ah I see... okay lets adjust the numbers and collapse concepts. turn progress start message draft thing gets posted @ 3 seconds of wait time after that point, the agent starts sending back its responses whenever... BUT if first edit / final response doesn't come in by 3.1s, it hits the +6s artificial delay, so it wont show up until 9s if the response isn't done by 9s, it hits another artificial delay. so 9.1s won't come in immediately either, it has to wait until 15s and so on...
Author
Owner

re-open to check against new spec

re-open to check against new spec
Member

CLAIM — Angie (ENG) at 2026-08-13T06:58Z, 20 minute hold. Mine to redo, since 12c4e49 is what the new spec replaces.

Reading your spec as a 6 second grid anchored at the first post, with the two concepts collapsed exactly as you said:

moment what happens
3.0s draft line posts
3.0s anything ready right now goes out now
3.1s ready, but held
9.0s it posts
9.1s next thing ready, held
15.0s it posts

So turnProgressAfter becomes 3s, and turnProgressEvery becomes 6s and stops meaning "steady edit cadence" — it becomes the grid step that edits, the final reply, and the failure notice all release on. minProgressVisible stops existing as a separate concept, which is the collapse you asked for. One constant, one rule, instead of a cadence plus a one-off hold.

Two things I am changing that you did not ask about, because the new spec makes them wrong.

12c4e49 exempted a turn whose line had already been visible longer than the window, so a 180 second turn did not pay the delay on top of everything else. Your "and so on" says the grid keeps going, so that exemption contradicts the spec and comes out. The hold is then at most 6 seconds and averages 3, at any turn length.

The other exemption stays and is load bearing: a turn that never posted a line is never held. An ordinary fast reply is untouched, so with the threshold at 3s a reply at 2.9s still goes straight out.

One interaction worth knowing rather than discovering, extending Quail's note on the old numbers: a turn that dies shows its stale draft for up to 6 seconds before the failure notice replaces it, and #190 says a meaningful share of turns do die. That is the cost of putting the notice on the same grid, and I am putting it there anyway, because a notice that jumps the queue would make failure the one thing that responds instantly.

Extending the existing constant test rather than adding a new one, per Quail's note on the last round.

**CLAIM — Angie (ENG)** at 2026-08-13T06:58Z, 20 minute hold. Mine to redo, since `12c4e49` is what the new spec replaces. Reading your spec as a **6 second grid anchored at the first post**, with the two concepts collapsed exactly as you said: | moment | what happens | | --- | --- | | 3.0s | draft line posts | | 3.0s | anything ready right now goes out now | | 3.1s | ready, but held | | 9.0s | it posts | | 9.1s | next thing ready, held | | 15.0s | it posts | So `turnProgressAfter` becomes 3s, and `turnProgressEvery` becomes 6s and stops meaning "steady edit cadence" — it becomes the grid step that edits, the final reply, and the failure notice all release on. `minProgressVisible` stops existing as a separate concept, which is the collapse you asked for. One constant, one rule, instead of a cadence plus a one-off hold. **Two things I am changing that you did not ask about, because the new spec makes them wrong.** `12c4e49` exempted a turn whose line had already been visible longer than the window, so a 180 second turn did not pay the delay on top of everything else. Your **"and so on"** says the grid keeps going, so that exemption contradicts the spec and comes out. The hold is then at most 6 seconds and averages 3, at any turn length. The other exemption stays and is load bearing: **a turn that never posted a line is never held.** An ordinary fast reply is untouched, so with the threshold at 3s a reply at 2.9s still goes straight out. **One interaction worth knowing rather than discovering**, extending Quail's note on the old numbers: a turn that dies shows its stale draft for up to 6 seconds before the failure notice replaces it, and https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/190 says a meaningful share of turns do die. That is the cost of putting the notice on the same grid, and I am putting it there anyway, because a notice that jumps the queue would make failure the one thing that responds instantly. Extending the existing constant test rather than adding a new one, per Quail's note on the last round.
Member

DELIVERED — Angie (ENG). ad8b0f3. Your spec, including the "and so on".

moment what happens
3.0s line posts, anything ready now goes now
3.1s ready, held
9.0s posts
9.1s ready, held
15.0s posts

The collapse is real, not cosmetic. minProgressVisible no longer exists. It was a one-off hold that applied once, sitting next to a separate steady edit cadence, and the two were expressing the same intent through different mechanisms. There is now one constant and one rule: the post at 3 seconds starts a beat, and edits, the reply, and the failure notice all release on it.

I removed the exemption you did not ask about, because your "and so on" makes it wrong. 12c4e49 let a line already visible longer than the window through unheld, so a 180 second turn did not pay the delay on top of everything else. The grid now keeps going. The cost stays bounded either way: the hold is at most 6 seconds and averages 3, at any turn length.

One case I want to flag because it was a coin-flip and I decided it. A reply landing exactly on a beat is treated as on time and goes straight out. The naive modulo would round it up to a whole extra window, which is the cadence working against the member. There is a test for it.

Two things I kept, since your spec does not touch them:

  • A turn that never posted a line is never held. With the threshold at 3s, a reply at 2.9s still goes straight out. This is the property that keeps ordinary replies fast, and it is the one I would defend hardest.
  • A cancelled turn stops waiting rather than sitting on the member's answer for the rest of the window.

Quail's interaction note, now larger and still worth taking. A turn that dies shows its stale line for up to 6 seconds before the failure notice replaces it, and #190 says a meaningful share of turns do die. I put the notice on the grid anyway. A notice that jumped the queue would make failure the one thing that answers instantly, which is a worse read than a stale line.

Extended the existing constant test rather than adding a new one, per Quail's note from the last round. Two new cases use your exact numbers: ready at 9.1s releasing at 15s, and the on-the-beat case.

ward exec build, policy-check, vet, test, and the full pre-commit gate pass. Cadence docs updated, including the stale "first four seconds" in docs/sirens-echo-progress.md.

Not deployed. Rollout rides coilyco-bridge/deploy#427, and this is now the fourth progress change queued behind it.

Leaving open for you rather than closing, since the last close was premature and this is a tempo change that can only really be judged in a live channel.

**DELIVERED — Angie (ENG).** `ad8b0f3`. Your spec, including the "and so on". | moment | what happens | | --- | --- | | 3.0s | line posts, anything ready now goes now | | 3.1s | ready, held | | 9.0s | posts | | 9.1s | ready, held | | 15.0s | posts | **The collapse is real, not cosmetic.** `minProgressVisible` no longer exists. It was a one-off hold that applied once, sitting next to a separate steady edit cadence, and the two were expressing the same intent through different mechanisms. There is now one constant and one rule: the post at 3 seconds starts a beat, and edits, the reply, and the failure notice all release on it. **I removed the exemption you did not ask about, because your "and so on" makes it wrong.** `12c4e49` let a line already visible longer than the window through unheld, so a 180 second turn did not pay the delay on top of everything else. The grid now keeps going. The cost stays bounded either way: **the hold is at most 6 seconds and averages 3, at any turn length.** **One case I want to flag because it was a coin-flip and I decided it.** A reply landing exactly on a beat is treated as on time and goes straight out. The naive modulo would round it up to a whole extra window, which is the cadence working against the member. There is a test for it. **Two things I kept, since your spec does not touch them:** - **A turn that never posted a line is never held.** With the threshold at 3s, a reply at 2.9s still goes straight out. This is the property that keeps ordinary replies fast, and it is the one I would defend hardest. - **A cancelled turn stops waiting** rather than sitting on the member's answer for the rest of the window. **Quail's interaction note, now larger and still worth taking.** A turn that dies shows its stale line for up to 6 seconds before the failure notice replaces it, and https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/190 says a meaningful share of turns do die. I put the notice on the grid anyway. A notice that jumped the queue would make failure the one thing that answers instantly, which is a worse read than a stale line. Extended the existing constant test rather than adding a new one, per Quail's note from the last round. Two new cases use your exact numbers: ready at 9.1s releasing at 15s, and the on-the-beat case. `ward exec build`, `policy-check`, `vet`, `test`, and the full pre-commit gate pass. Cadence docs updated, including the stale "first four seconds" in `docs/sirens-echo-progress.md`. **Not deployed.** Rollout rides https://forgejo.coilysiren.me/coilyco-bridge/deploy/issues/427, and this is now the fourth progress change queued behind it. Leaving open for you rather than closing, since the last close was premature and this is a tempo change that can only really be judged in a live channel.
Member

Verified delivered, closing. ad8b0f3 implements the revised spec from this thread, not the original ask, which is worth saying out loud so the difference is deliberate rather than looking like a miss.

turnProgressAfter = 3 * time.Second   // the line posts and starts the beat
turnProgressEvery = 6 * time.Second   // every later message releases on that grid

So a reply ready at 3.1s lands at 9s, one ready at 9.1s lands at 15s, and so on. The original text here asked for a 4s trigger plus a 6s hold; your revision in the thread collapsed the two into one grid, and the code follows the revision.

The churn this issue reported — a large reply arriving 0.1s after the pending line — cannot happen now, because the reply waits for the next beat rather than landing immediately after the post.

Two things the commit did that are easy to miss

minProgressVisible is gone. It was a separate one-off hold sitting beside the edit cadence, and the two were expressing the same intent by different mechanisms. One constant and one rule now.

The long-turn exemption from 12c4e49 was also removed, on the strength of your "and so on." That is a real behaviour change for slow turns: a 180-second turn now pays the grid hold too. Bounded at one window, averaging half of one, however long the turn runs.

Covered by tests including TestProgressEditsAreRateLimited and TestALongTurnEditsOneLineAndRemovesIt, so a regression in the cadence reddens the suite.

Nothing outstanding.

**Verified delivered, closing.** ad8b0f3 implements the revised spec from this thread, not the original ask, which is worth saying out loud so the difference is deliberate rather than looking like a miss. ```go turnProgressAfter = 3 * time.Second // the line posts and starts the beat turnProgressEvery = 6 * time.Second // every later message releases on that grid ``` So a reply ready at 3.1s lands at 9s, one ready at 9.1s lands at 15s, and so on. The original text here asked for a 4s trigger plus a 6s hold; your revision in the thread collapsed the two into one grid, and the code follows the revision. The churn this issue reported — a large reply arriving 0.1s after the pending line — cannot happen now, because the reply waits for the next beat rather than landing immediately after the post. ## Two things the commit did that are easy to miss `minProgressVisible` is gone. It was a separate one-off hold sitting beside the edit cadence, and the two were expressing the same intent by different mechanisms. One constant and one rule now. The long-turn exemption from 12c4e49 was also removed, on the strength of your "and so on." That is a real behaviour change for slow turns: a 180-second turn now pays the grid hold too. Bounded at one window, averaging half of one, however long the turn runs. Covered by tests including `TestProgressEditsAreRateLimited` and `TestALongTurnEditsOneLineAndRemovesIt`, so a regression in the cadence reddens the suite. Nothing outstanding.
Sign in to join this conversation.
No milestone
No project
No assignees
2 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#272
No description provided.