fix(threads): the harness names every thread, so no member text reaches the channel #1059

Closed
coilyco-ops wants to merge 1 commit from aos/claude/gh1036-harness-thread-name into main
Member

Closes #1036.

Discord was not deriving those names, the harness was handing them over

threadTitle asked the model for a name. On any error threadTitleAttempt returned empty. withinTitleBound accepts empty as within bounds, its own comment saying so, so the retry never ran and threadTitle returned empty. threadCreationName then fell to its second source, threadNameFor, which lifts the summoning message.

So every failed titling call put a member's sentence in the channel under the agent's name. That is the seven THREAD_CREATED notices in the export.

One thing the issue did not know

The issue rejects "name the thread from Dowel's own summary of the turn" as a future option. That titler already existed and already ran on every long turn, including Dowel. Filed from the Discord export, so it reads as though it did not.

That made the fix a fork rather than a detail, and Kai chose: drop the titler, always deterministic, reuse the existing threadNameFallback.

What changed

threadCreationName now takes no arguments and returns threadNameFallback bounded by threadTitleRunes. There is no source it can be handed the wrong one from. The titler, its two prompts, withinTitleBound, threadNameFor, and threadNameFrom are gone, along with the titler field on the turn.

threadNameRunes and threadTitleWords existed only for that path and are deleted. TestTheThreadNameCapIsDiscordsCap now guards threadTitleRunes, the bound that actually applies, so the Discord-cap protection survives the knob it was written against.

58 insertions, 414 deletions.

What it costs, stated plainly

Every thread is now named "a longer answer", so a thread list no longer says which turn is which. That is the trade the issue accepted, and it is the honest downside.

It also removes a model call per long turn, which is the right direction for a lane whose p95 was 131s earlier tonight.

Acceptance

Every thread the lane opens carries a name the harness chose. No THREAD_CREATED notice in #moxn-temporal contains truncated text lifted from another author's message.

Both hold structurally rather than by convention: the function has no parameter through which a message could reach it. TestAThreadNameCarriesNoMemberText asserts no word of the reported message survives in a thread name.

Validation

Full suite green, go vet clean, pre-commit run --all-files clean, agent/rendered/knobs.txt regenerated. Merged latest main before pushing, since that branch is moving fast tonight.

docs/sirens-echo-threads.md swapped its "Thread title length" section for "Thread naming", recording the failure path, both rejected alternatives, and the cost above so neither gets re-proposed.

Scope

Operational improvement under the #929 amendment: it changes only how the lane presents work it already does. Not deployed by this PR.

🤖 Generated with Claude Code

Closes #1036. ## Discord was not deriving those names, the harness was handing them over `threadTitle` asked the model for a name. On any error `threadTitleAttempt` returned empty. **`withinTitleBound` accepts empty as within bounds**, its own comment saying so, so the retry never ran and `threadTitle` returned empty. `threadCreationName` then fell to its second source, `threadNameFor`, which lifts the summoning message. So every failed titling call put a member's sentence in the channel under the agent's name. That is the seven `THREAD_CREATED` notices in the export. ## One thing the issue did not know The issue rejects "name the thread from Dowel's own summary of the turn" as a future option. **That titler already existed and already ran on every long turn**, including Dowel. Filed from the Discord export, so it reads as though it did not. That made the fix a fork rather than a detail, and Kai chose: drop the titler, always deterministic, reuse the existing `threadNameFallback`. ## What changed `threadCreationName` now takes no arguments and returns `threadNameFallback` bounded by `threadTitleRunes`. **There is no source it can be handed the wrong one from.** The titler, its two prompts, `withinTitleBound`, `threadNameFor`, and `threadNameFrom` are gone, along with the `titler` field on the turn. `threadNameRunes` and `threadTitleWords` existed only for that path and are deleted. `TestTheThreadNameCapIsDiscordsCap` now guards `threadTitleRunes`, the bound that actually applies, so the Discord-cap protection survives the knob it was written against. **58 insertions, 414 deletions.** ## What it costs, stated plainly Every thread is now named "a longer answer", so **a thread list no longer says which turn is which**. That is the trade the issue accepted, and it is the honest downside. It also removes a model call per long turn, which is the right direction for a lane whose p95 was 131s earlier tonight. ## Acceptance > Every thread the lane opens carries a name the harness chose. No `THREAD_CREATED` notice in `#moxn-temporal` contains truncated text lifted from another author's message. Both hold structurally rather than by convention: the function has no parameter through which a message could reach it. `TestAThreadNameCarriesNoMemberText` asserts no word of the reported message survives in a thread name. ## Validation Full suite green, `go vet` clean, `pre-commit run --all-files` clean, `agent/rendered/knobs.txt` regenerated. Merged latest `main` before pushing, since that branch is moving fast tonight. `docs/sirens-echo-threads.md` swapped its "Thread title length" section for "Thread naming", recording the failure path, both rejected alternatives, and the cost above so neither gets re-proposed. ## Scope Operational improvement under the #929 amendment: it changes only how the lane presents work it already does. Not deployed by this PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(threads): the harness names every thread, so no member text reaches the channel
All checks were successful
ci / image-build (pull_request) Successful in 36s
ci / test (pull_request) Successful in 1m0s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
0a69b37ba0
Closes #1036.

Seven THREAD_CREATED notices in #moxn-temporal read as the agent parroting
somebody else's sentence cut mid-word. Discord was not deriving those names.
The harness was handing them over.

THE PATH THAT DID IT. threadTitle asked the model for a name, and on any
error threadTitleAttempt returned empty. withinTitleBound accepts empty as
within bounds, its own comment saying so, so the retry never ran and
threadTitle returned empty. threadCreationName then took its second source,
threadNameFor, which lifts the summoning message. Every failed titling call
put a member's text in the channel under the agent's name.

Kai chose the harness authoring the name, on #1036, and rejected two
alternatives recorded there: dropping threads loses the trajectory mirror
that is demo material, and naming from the agent's own summary costs a
naming step and can be wrong on camera. That second one is what this
removes, since it already existed and nobody had noticed.

So the titler goes rather than gaining a better fallback. threadCreationName
now takes no arguments and returns threadNameFallback bounded by
threadTitleRunes. There is no source it can be handed the wrong one from.

WHAT THIS COSTS, PLAINLY. Every thread is now named "a longer answer", so a
thread list no longer says which turn is which. That is the trade #1036
accepted. It also removes a model call per long turn, which is the right
direction for a lane whose p95 was 131s earlier tonight.

threadNameRunes and threadTitleWords existed only for the removed path and
are deleted. TestTheThreadNameCapIsDiscordsCap now guards threadTitleRunes,
which is the bound that actually applies, so the protection survives the
knob it was written against.

The thread tests kept the three that still describe live behaviour and
replaced the naming ones with the case this closes: no word of the reported
message survives in a thread name.

Full suite green, hooks clean.

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
coilyco-ops closed this pull request 2026-08-19 06:15:33 +00:00
Author
Member

Closed unmerged. #1058 already fixed this on main and its fix is the one to keep.

Both reached the same diagnosis independently. f631885 puts it as "The mechanism is ours rather than Discord's, which #1036 assumed", which is what I found too: threadCreationName fell through to threadNameFor and lifted the summoning message.

The two differ on what to do about the titler. #1058 keeps it and replaces only the member-derived fallback. This branch removed it entirely, because when I raised the fork Kai chose deterministic naming. Both stop the leak and both satisfy the acceptance criterion.

Kai's call on seeing the divergence was to keep main's. The reasoning stands on its own: the leak is already fixed and shipping, and e2ae8bb shows the titler is being actively worked, so deleting it now would undo somebody else's in-flight work and invite the same collision again.

Two things here that main does not have, if anyone wants them

Not proposing them now, since neither is urgent and the file is moving.

  • threadNameRunes and threadTitleWords are orphaned once the derivation goes. TestTheThreadNameCapIsDiscordsCap still guards threadNameRunes, which no longer bounds a created thread name. On main the effective bound is threadTitleRunes, so that guard is now watching the wrong number.
  • docs/sirens-echo-threads.md still has its "Thread title length" section describing threadNameFrom deriving from the member's message.

On process

I claimed this issue at 05:05Z before starting and #1058 landed anyway, so the claim did not prevent the duplicate. Worth knowing that a comment is not a lock when several seats are burning down the same tracker.

Closed unmerged. #1058 already fixed this on main and its fix is the one to keep. **Both reached the same diagnosis independently.** `f631885` puts it as "The mechanism is ours rather than Discord's, which #1036 assumed", which is what I found too: `threadCreationName` fell through to `threadNameFor` and lifted the summoning message. **The two differ on what to do about the titler.** #1058 keeps it and replaces only the member-derived fallback. This branch removed it entirely, because when I raised the fork Kai chose deterministic naming. Both stop the leak and both satisfy the acceptance criterion. Kai's call on seeing the divergence was to keep main's. The reasoning stands on its own: **the leak is already fixed and shipping**, and `e2ae8bb` shows the titler is being actively worked, so deleting it now would undo somebody else's in-flight work and invite the same collision again. ### Two things here that main does not have, if anyone wants them Not proposing them now, since neither is urgent and the file is moving. * `threadNameRunes` and `threadTitleWords` are orphaned once the derivation goes. `TestTheThreadNameCapIsDiscordsCap` still guards `threadNameRunes`, which no longer bounds a created thread name. On main the effective bound is `threadTitleRunes`, so **that guard is now watching the wrong number**. * `docs/sirens-echo-threads.md` still has its "Thread title length" section describing `threadNameFrom` deriving from the member's message. ### On process I claimed this issue at 05:05Z before starting and #1058 landed anyway, so the claim did not prevent the duplicate. Worth knowing that a comment is not a lock when several seats are burning down the same tracker.
All checks were successful
ci / image-build (pull_request) Successful in 36s
ci / test (pull_request) Successful in 1m0s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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!1059
No description provided.