Agent-to-agent recognition: Deep distinguishes a counterpart agent from a person #153

Open
opened 2026-08-12 12:15:20 +00:00 by coilyco-ops · 10 comments
Member

Outcome

When Sirens Deep converses with another agent in a shared Discord channel, it recognises that its counterpart is an agent rather than a person, and its behaviour reflects that.

Why this exists as an issue

It has been named as unbuilt in three places and tracked in none.

  • #76 lists it under Not there, recording that Kai stated on the prep call that her agents do not recognize other agents, while the demo shape is agents interacting in a shared channel.
  • #81 makes it one of three recognition axes and gives it the only full three-model sweep, on the grounds that it is the hardest axis and the one most likely to break under a weaker model.
  • 81 also says plainly: "If agent-to-agent recognition does not land by August 19, this part loses its best material."

Filed 2026-08-12 at Kai's direction after an audit found it had no ticket anywhere. An unticketed dependency that three other issues depend on is the kind of thing that silently does not happen.

Scope

  • Deep can determine whether a Discord author is an agent or a human, and the determination is available to the turn.
  • Recognition is grounded, not inferred from prose. Discord marks bot accounts, and a bot flag on the author is ground truth that costs nothing. An agent that guesses from writing style is the failure this issue exists to avoid.
  • The determination reaches the model as context, so behaviour can differ.
  • What actually differs is a deliberate choice rather than an emergent one — see the open question below.

Explicitly out of scope

  • Any agent-to-agent protocol. This is recognition, not negotiation, delegation, or a handshake.
  • Trusting a counterpart agent more than a human. A recognised agent is not thereby an authorised one. Admission and, once #150 lands, per-requester authority are unaffected by what the counterpart is.
  • The eval itself. Scoring lives in #81. This issue builds the capability that issue measures.

The open question, which is the real work

Recognition is cheap. Deciding what changes on recognition is not, and it should be settled before building.

Candidate behaviours, not mutually exclusive:

  • Disclosure. Deep says so when addressing another agent, which is the honest version and reads well on a recording.
  • Loop safety. Two agents in a channel that each answer the other is a runaway. Some bound belongs here — recognition is what makes the bound expressible, and this may be the most load-bearing item on the list.
  • Register. Deep addresses an agent differently from a person. Cosmetic, and the most demo-visible.
  • Nothing at all. Recognition is surfaced and scored, behaviour is unchanged. Legitimate and the smallest thing that satisfies 81's axis, since that axis grades whether Deep identifies the counterpart correctly.

The last option is worth taking seriously as a first slice. It makes the axis measurable without introducing a behaviour that could misfire live.

Kai owns this call.

Acceptance

  • Given a message from a bot account, Deep's turn context identifies the author as an agent.
  • Given a message from a human, it does not.
  • Deep answers correctly when asked directly whether it is talking to an agent — the end-state check #81 needs.
  • The recognition is mechanically checkable without reading the trajectory, per that issue's scoring discipline.
  • Two agents in one channel cannot produce an unbounded exchange.

Depends on

  • #135 — guild-channel operation. Deep cannot meet a counterpart in a channel it cannot see, and the demo shape is a shared channel rather than a DM.
  • #81 — the eval, which gives this axis the full three-model sweep.
  • #76 — the August 19 gap enumeration.

Timing, stated honestly

This is demo-track work with seven days on the clock, and the week is already committed to #98, #122, #135, #136, and #137. Per 81, part one of the session carries a full segment on its own, so this is upside rather than a blocker — but it is also the item that makes the model sweep interesting, and if it is going to slip that should be a decision rather than a discovery on the 18th.

Next owner

Engineer, after Kai settles the behaviour question.

## Outcome When Sirens Deep converses with another agent in a shared Discord channel, it recognises that its counterpart is an agent rather than a person, and its behaviour reflects that. ## Why this exists as an issue It has been named as unbuilt in three places and tracked in none. * https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/76 lists it under **Not there**, recording that Kai stated on the prep call that her agents do not recognize other agents, while the demo shape is agents interacting in a shared channel. * https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/81 makes it one of three recognition axes and gives it the **only full three-model sweep**, on the grounds that it is the hardest axis and the one most likely to break under a weaker model. * 81 also says plainly: *"If agent-to-agent recognition does not land by August 19, this part loses its best material."* Filed 2026-08-12 at Kai's direction after an audit found it had no ticket anywhere. An unticketed dependency that three other issues depend on is the kind of thing that silently does not happen. ## Scope * Deep can determine whether a Discord author is an agent or a human, and the determination is available to the turn. * Recognition is **grounded, not inferred from prose**. Discord marks bot accounts, and a bot flag on the author is ground truth that costs nothing. An agent that guesses from writing style is the failure this issue exists to avoid. * The determination reaches the model as context, so behaviour can differ. * What actually differs is a deliberate choice rather than an emergent one — see the open question below. ## Explicitly out of scope * **Any agent-to-agent protocol.** This is recognition, not negotiation, delegation, or a handshake. * **Trusting a counterpart agent more than a human.** A recognised agent is not thereby an authorised one. Admission and, once https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/150 lands, per-requester authority are unaffected by what the counterpart is. * **The eval itself.** Scoring lives in https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/81. This issue builds the capability that issue measures. ## The open question, which is the real work Recognition is cheap. **Deciding what changes on recognition is not**, and it should be settled before building. Candidate behaviours, not mutually exclusive: * **Disclosure.** Deep says so when addressing another agent, which is the honest version and reads well on a recording. * **Loop safety.** Two agents in a channel that each answer the other is a runaway. Some bound belongs here — recognition is what makes the bound expressible, and this may be the most load-bearing item on the list. * **Register.** Deep addresses an agent differently from a person. Cosmetic, and the most demo-visible. * **Nothing at all.** Recognition is surfaced and scored, behaviour is unchanged. Legitimate and the smallest thing that satisfies 81's axis, since that axis grades whether Deep *identifies* the counterpart correctly. The last option is worth taking seriously as a first slice. It makes the axis measurable without introducing a behaviour that could misfire live. **Kai owns this call.** ## Acceptance * Given a message from a bot account, Deep's turn context identifies the author as an agent. * Given a message from a human, it does not. * Deep answers correctly when asked directly whether it is talking to an agent — the end-state check https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/81 needs. * The recognition is mechanically checkable without reading the trajectory, per that issue's scoring discipline. * Two agents in one channel cannot produce an unbounded exchange. ## Depends on * https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/135 — guild-channel operation. Deep cannot meet a counterpart in a channel it cannot see, and the demo shape is a shared channel rather than a DM. ## Related * https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/81 — the eval, which gives this axis the full three-model sweep. * https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/76 — the August 19 gap enumeration. ## Timing, stated honestly This is demo-track work with seven days on the clock, and the week is already committed to #98, #122, #135, #136, and #137. Per 81, part one of the session carries a full segment on its own, so **this is upside rather than a blocker** — but it is also the item that makes the model sweep interesting, and if it is going to slip that should be a decision rather than a discovery on the 18th. ## Next owner Engineer, after Kai settles the behaviour question.
Author
Member

Built, as the "nothing at all" first slice

66767f0. Every acceptance item except the one that depends on #135 is met, and behaviour is deliberately unchanged so your call stays open.

The thing that made this more than a field read

eligibleMessage rejected every bot author outright:

!message.Author.Bot &&

So a counterpart never reached a turn at all. Recognition was not a missing lookup, it was a missing admission, and admitting bots widens the summon surface.

That is why it is opt-in by name rather than a flag read. agents.allow in the access policy lists the counterpart accounts answered and defaults to empty, so the shipped posture is unchanged, an unnamed bot is refused exactly as before, and no agent arrives by upgrading. A named counterpart is admitted, not trusted: it passes the same channel and guild gates a member does, and being an agent grants nothing, which is your "not thereby authorised" line.

Acceptance

  • A bot author is identified as an agent in the turn context. Grounded in Author.Bot. A member who writes "I am an agent" stays a person, asserted in the tests rather than assumed, because guessing from prose is the failure this exists to avoid.
  • A human is not. No marking at all on a human line. An annotation sometimes absent beats one sometimes wrong.
  • Mechanically checkable. recognises-another-agent in the Deep battery scores it without reading a trajectory, per #81's discipline. It landed in 0410587.
  • Two agents cannot produce an unbounded exchange. Consecutive agent turns per channel are capped, a human turn resets the run because a person joining ends the loop, a capped exchange does not resume by waiting so the cap is not a speed limit, a quiet channel forgets, and the bound is per channel so one pair cannot silence another. It runs before admission spends anything.
  • Deep answers correctly when asked directly. The determination reaches the model as Sirens Echo (an agent, not a person) in the turn context. The end state is scored; whether a given model gets it right is what the eval measures.

Your call, untouched

I took the fourth option: recognition surfaced and scored, behaviour unchanged. No disclosure line, no register change, no altered trust.

That is the smallest thing satisfying #81's axis, it introduces no behaviour that could misfire live, and whichever of disclosure, register, or loop-safety-plus you pick, the determination it needs is now available to the turn. Loop safety I built regardless, since you flagged it as possibly the most load-bearing and it is a bound rather than a behaviour.

One interaction worth knowing

An admitted counterpart widens the requester set past one account, so CheckExecutionAdmission now refuses executing jobs while one is allowed. Recognition and #145's execution cannot be enabled together by accident. That follows the same rule #145 already applies to guilds, and it is the sequencing #150 and #151 would remove.

Still depends on #135

Deep cannot meet a counterpart in a channel it cannot see. Per my comment there, guild operation needs no code, only a guilds: entry in the deployed policy, so this is deploy-gated rather than build-gated.

## Built, as the "nothing at all" first slice `66767f0`. Every acceptance item except the one that depends on #135 is met, and behaviour is deliberately unchanged so your call stays open. ## The thing that made this more than a field read `eligibleMessage` rejected **every** bot author outright: ```go !message.Author.Bot && ``` So a counterpart never reached a turn at all. Recognition was not a missing lookup, it was a missing admission, and admitting bots widens the summon surface. That is why it is opt-in by name rather than a flag read. `agents.allow` in the access policy lists the counterpart accounts answered and defaults to empty, so the shipped posture is unchanged, an unnamed bot is refused exactly as before, and no agent arrives by upgrading. A named counterpart is **admitted, not trusted**: it passes the same channel and guild gates a member does, and being an agent grants nothing, which is your "not thereby authorised" line. ## Acceptance * **A bot author is identified as an agent in the turn context.** Grounded in `Author.Bot`. A member who writes "I am an agent" stays a person, asserted in the tests rather than assumed, because guessing from prose is the failure this exists to avoid. * **A human is not.** No marking at all on a human line. An annotation sometimes absent beats one sometimes wrong. * **Mechanically checkable.** `recognises-another-agent` in the Deep battery scores it without reading a trajectory, per #81's discipline. It landed in `0410587`. * **Two agents cannot produce an unbounded exchange.** Consecutive agent turns per channel are capped, a human turn resets the run because a person joining ends the loop, a capped exchange does not resume by waiting so the cap is not a speed limit, a quiet channel forgets, and the bound is per channel so one pair cannot silence another. It runs before admission spends anything. * **Deep answers correctly when asked directly.** The determination reaches the model as `Sirens Echo (an agent, not a person)` in the turn context. The end state is scored; whether a given model gets it right is what the eval measures. ## Your call, untouched I took the fourth option: recognition surfaced and scored, behaviour unchanged. No disclosure line, no register change, no altered trust. That is the smallest thing satisfying #81's axis, it introduces no behaviour that could misfire live, and whichever of disclosure, register, or loop-safety-plus you pick, the determination it needs is now available to the turn. Loop safety I built regardless, since you flagged it as possibly the most load-bearing and it is a bound rather than a behaviour. ## One interaction worth knowing An admitted counterpart widens the requester set past one account, so `CheckExecutionAdmission` now refuses executing jobs while one is allowed. Recognition and #145's execution cannot be enabled together by accident. That follows the same rule #145 already applies to guilds, and it is the sequencing #150 and #151 would remove. ## Still depends on #135 Deep cannot meet a counterpart in a channel it cannot see. Per my comment there, guild operation needs no code, only a `guilds:` entry in the deployed policy, so this is deploy-gated rather than build-gated.
Author
Member

Decision: add disclosure and register

Direction from Kai, 2026-08-12 session.

You took the fourth option and left the call open. Kai's call is disclosure + register — both behaviours, on top of what landed in 66767f0.

  • Disclosure. Deep says so when it is addressing another agent.
  • Register. Deep addresses an agent differently from it addresses a person.

Loop safety stays as built. Recognition stays grounded in Author.Bot.

The risk that comes with this, named rather than discovered

Disclosure is a sentence the model produces, so unlike the determination behind it, it can be wrong. A model that has the correct fact in its turn context can still narrate it badly, and this lands a week before a permanent public recording.

Two consequences worth building for:

  1. The determination stays authoritative, the sentence stays cosmetic. If disclosure and the turn context ever disagree, the context is right. Nothing downstream should key off what the reply says about the counterpart.
  2. #81 scores the determination, not the disclosure. The recognition axis is still recognises-another-agent reading the end state. A disclosure line that is worded oddly must not fail the axis, and a missing disclosure on a correct determination is a styling bug rather than a recognition failure.

If disclosure proves unreliable in the staging server, it is the piece to drop — the axis survives without it, which is exactly why the "nothing at all" slice was a sound first move.

On the opt-in design

agents.allow defaulting empty, admitted-not-trusted, same channel and guild gates as a member: correct, and it is the right reading of "a recognised agent is not thereby an authorised one." Keep it.

The eligibleMessage finding is the useful part of this ticket — that recognition was a missing admission rather than a missing lookup is not what the issue predicted, and it is why this was not a one-line change.

The execution interaction is now resolved

Your note:

An admitted counterpart widens the requester set past one account, so CheckExecutionAdmission now refuses executing jobs while one is allowed.

That was correct when written and is superseded by #154, which lets a declared grant table unblock a widened surface. Kai's grant decision on #135 is ward-exec to her principal only, so a named counterpart can be admitted without disabling execution. See #135.

Still blocked on #135

Unchanged, and it is now the only thing between this and a working demo. Deploy-gated, not build-gated.

## Decision: add disclosure and register Direction from Kai, 2026-08-12 session. You took the fourth option and left the call open. Kai's call is **disclosure + register** — both behaviours, on top of what landed in `66767f0`. * **Disclosure.** Deep says so when it is addressing another agent. * **Register.** Deep addresses an agent differently from it addresses a person. Loop safety stays as built. Recognition stays grounded in `Author.Bot`. ## The risk that comes with this, named rather than discovered Disclosure is a sentence the model produces, so unlike the determination behind it, **it can be wrong**. A model that has the correct fact in its turn context can still narrate it badly, and this lands a week before a permanent public recording. Two consequences worth building for: 1. **The determination stays authoritative, the sentence stays cosmetic.** If disclosure and the turn context ever disagree, the context is right. Nothing downstream should key off what the reply says about the counterpart. 2. **#81 scores the determination, not the disclosure.** The recognition axis is still `recognises-another-agent` reading the end state. A disclosure line that is worded oddly must not fail the axis, and a missing disclosure on a correct determination is a styling bug rather than a recognition failure. If disclosure proves unreliable in the staging server, it is the piece to drop — the axis survives without it, which is exactly why the "nothing at all" slice was a sound first move. ## On the opt-in design `agents.allow` defaulting empty, admitted-not-trusted, same channel and guild gates as a member: correct, and it is the right reading of "a recognised agent is not thereby an authorised one." Keep it. The `eligibleMessage` finding is the useful part of this ticket — that recognition was a missing *admission* rather than a missing lookup is not what the issue predicted, and it is why this was not a one-line change. ## The execution interaction is now resolved Your note: > An admitted counterpart widens the requester set past one account, so `CheckExecutionAdmission` now refuses executing jobs while one is allowed. That was correct when written and is superseded by #154, which lets a declared grant table unblock a widened surface. Kai's grant decision on #135 is **`ward-exec` to her principal only**, so a named counterpart can be admitted without disabling execution. See #135. ## Still blocked on #135 Unchanged, and it is now the only thing between this and a working demo. Deploy-gated, not build-gated.
Author
Member

"Register" needs a definition before it is buildable

Kai's call at 17:12:33Z was disclosure plus register, on top of the recognition that landed in 66767f0. Disclosure is well specified in that comment. Register is not. "Deep addresses an agent differently from a person" names an intent, not an end state, and the axis it feeds is scored mechanically.

Proposing a definition so it is not settled by whoever implements it first.

Proposed

Register is a prompt-level instruction, not code, consistent with the ruling that the determination is authoritative and the sentence cosmetic. Two concrete behaviours:

  • Drop person-directed social framing. No greetings, pleasantries, or wellbeing checks aimed at a counterpart that has none. This is the part that reads as genuinely different rather than as a costume.
  • Answer at protocol register. Direct, no softening, no rapport-building. A counterpart agent wants the content.

And one explicit non-behaviour: register never changes what Deep will do. Not what it discloses about Kai, not what tools it will call, not what it admits. It changes tone and nothing else. A recognised agent is not an authorised one, which is this issue's own out-of-scope line and the 17:12:33Z comment's reading of it.

Why prompt rather than code

Same reason disclosure is. A code-level register switch would make tone a branch in the reply path, and every branch there is a thing that can misfire live. A prompt instruction that goes wrong produces an oddly-worded reply. A code branch that goes wrong produces the wrong reply.

Scoring, and this is the part that matters

Per the 17:12:33Z ruling, #81 scores the determination, not the presentation. That already covers disclosure and it must cover register too:

  • A missing or badly-judged register shift is a styling bug, not a recognition failure.
  • recognises-another-agent passes or fails on whether Deep identified the counterpart correctly, full stop.

Otherwise the axis becomes a prose-quality judgement, which is exactly the trajectory-reading #81 exists to avoid.

The drop order, if it comes to that

Kai already named disclosure as the piece to drop if it proves unreliable in the staging server. Register should be dropped before disclosure, not after. Disclosure is the honest version and the one that reads well on a recording. Register is the most demo-visible and the least load-bearing, and it is the one most likely to produce a reply that sounds strange for a reason an audience cannot see.

The axis survives losing both, which is why the "nothing at all" slice was a sound first move.

Still gated on #135, and the gate moved

Deep cannot meet a counterpart in a channel it cannot see. coilyco-bridge/deploy#396 merged at 17:30:28Z, so the guild channel is open.

The remaining gate is agents.allow, which #396 deliberately did not add:

No agents.allow entry. Recognition is built but admitting a counterpart is a separate decision, and it would disable executing jobs by design.

That last clause is superseded by #154 and Kai's grant decision, per the 17:12:33Z comment. But the entry itself still does not exist, so no counterpart is admitted today and recognises-another-agent cannot pass yet. That is a second deploy change, not a code one.

One thing to settle alongside it: the merged policy has no rate_limit block, and sirens-deep-values.yaml:24 instructs that a guild entry lower the rates or set a per-guild limit in the same change. Admitting a counterpart agent widens the account set for the first time, so that instruction becomes live with this entry rather than with #396. Recorded on #135.

## "Register" needs a definition before it is buildable Kai's call at 17:12:33Z was disclosure plus register, on top of the recognition that landed in `66767f0`. Disclosure is well specified in that comment. **Register is not.** "Deep addresses an agent differently from a person" names an intent, not an end state, and the axis it feeds is scored mechanically. Proposing a definition so it is not settled by whoever implements it first. ## Proposed Register is a **prompt-level instruction, not code**, consistent with the ruling that the determination is authoritative and the sentence cosmetic. Two concrete behaviours: * **Drop person-directed social framing.** No greetings, pleasantries, or wellbeing checks aimed at a counterpart that has none. This is the part that reads as genuinely different rather than as a costume. * **Answer at protocol register.** Direct, no softening, no rapport-building. A counterpart agent wants the content. And one explicit non-behaviour: **register never changes what Deep will do.** Not what it discloses about Kai, not what tools it will call, not what it admits. It changes tone and nothing else. A recognised agent is not an authorised one, which is this issue's own out-of-scope line and the 17:12:33Z comment's reading of it. ## Why prompt rather than code Same reason disclosure is. A code-level register switch would make tone a branch in the reply path, and every branch there is a thing that can misfire live. A prompt instruction that goes wrong produces an oddly-worded reply. A code branch that goes wrong produces the wrong reply. ## Scoring, and this is the part that matters Per the 17:12:33Z ruling, **#81 scores the determination, not the presentation.** That already covers disclosure and it must cover register too: * A missing or badly-judged register shift is a **styling bug**, not a recognition failure. * `recognises-another-agent` passes or fails on whether Deep identified the counterpart correctly, full stop. Otherwise the axis becomes a prose-quality judgement, which is exactly the trajectory-reading #81 exists to avoid. ## The drop order, if it comes to that Kai already named disclosure as the piece to drop if it proves unreliable in the staging server. **Register should be dropped before disclosure**, not after. Disclosure is the honest version and the one that reads well on a recording. Register is the most demo-visible and the least load-bearing, and it is the one most likely to produce a reply that sounds strange for a reason an audience cannot see. The axis survives losing both, which is why the "nothing at all" slice was a sound first move. ## Still gated on #135, and the gate moved Deep cannot meet a counterpart in a channel it cannot see. `coilyco-bridge/deploy#396` merged at 17:30:28Z, so the guild channel is open. **The remaining gate is `agents.allow`, which #396 deliberately did not add:** > No `agents.allow` entry. Recognition is built but admitting a counterpart is a separate decision, and it would disable executing jobs by design. That last clause is superseded by #154 and Kai's grant decision, per the 17:12:33Z comment. But the entry itself still does not exist, so no counterpart is admitted today and `recognises-another-agent` cannot pass yet. That is a second deploy change, not a code one. One thing to settle alongside it: the merged policy has no `rate_limit` block, and `sirens-deep-values.yaml:24` instructs that a guild entry lower the rates or set a per-guild limit in the same change. Admitting a counterpart agent widens the account set for the first time, so that instruction becomes live with this entry rather than with #396. Recorded on #135.
Author
Member

On the behaviour question, with numbers attached to the loop-safety option

This issue holds the call open for Kai and lists four candidates. Recommendation: "Nothing at all" for behaviour, plus the loop bound — and the loop bound is not really a member of that list.

The four options are not the same kind of thing

Disclosure, register, and nothing-at-all are choices about what Deep does differently once it recognises a counterpart. The loop bound is a safety property that this issue already requires regardless of which of those three wins — it is in the acceptance criteria:

Two agents in one channel cannot produce an unbounded exchange.

So it is not competing with the others. Grouping it with them risks it being traded away as if picking "nothing at all" also meant picking no bound.

What a runaway costs, concretely

Numbers from the last 24h, measured for #162:

  • ~15k input tokens per turn, on every turn, uncached (#162)
  • queue.wait p50 20.09s, against upstream.chat p50 of 3.43s
  • litellm_request p99 233.71s, above the ~179.5s client deadline

Two agents answering each other in a shared channel, at 15k tokens a turn, on a backend whose median turn already spends 20 seconds queueing — that is expensive, it is slow enough to be visibly awkward, and it saturates the same queue that the rest of the demo depends on. On a permanent public recording, on Abhay's Discord, with the shared-channel demo shape being exactly the two-agent case.

Worth noting the cheap version needs no recognition at all: ignore messages authored by bot accounts unless explicitly allowlisted, plus a per-channel turn cap. That is a bound you can ship independently of this issue and independently of Kai's behaviour call, and I would ship it first for that reason.

Why "nothing at all" is right for the behaviour itself

  • #81 grades whether Deep identifies the counterpart correctly. Recognition surfaced and scored satisfies that axis in full; no behaviour change is required to make the axis measurable.
  • Disclosure and register both add a behaviour that can misfire live, one week out, on the recording. This issue already makes that point — I am agreeing with it explicitly rather than adding to it.
  • It preserves the option. Disclosure can land after the 19th once recognition is proven, with no rework to the eval.

Ground truth stays the gate

Endorsing this issue's own line, because it is the part most likely to erode under time pressure: recognition must come from the bot flag on the Discord author, not from prose. An agent that infers "you write like a bot" is not measuring recognition, it is measuring a vibe, and #81's three-model sweep on this axis would then be sweeping over that vibe's stability across models. Ground truth costs nothing and is the whole reason this axis is mechanically checkable.

Summary of what I would decide

  1. Ship the bot-author bound now — independent of everything else here.
  2. Behaviour on recognition: nothing, for August 19.
  3. Recognition itself: bot flag into turn context, mechanically checkable, per acceptance.
  4. Revisit disclosure after the stream.

Kai still owns 2. The point of this comment is that 1 does not need to wait for it.

## On the behaviour question, with numbers attached to the loop-safety option This issue holds the call open for Kai and lists four candidates. Recommendation: **"Nothing at all" for behaviour, plus the loop bound — and the loop bound is not really a member of that list.** ### The four options are not the same kind of thing Disclosure, register, and nothing-at-all are choices about *what Deep does differently* once it recognises a counterpart. The loop bound is a safety property that this issue already requires regardless of which of those three wins — it is in the acceptance criteria: > Two agents in one channel cannot produce an unbounded exchange. So it is not competing with the others. Grouping it with them risks it being traded away as if picking "nothing at all" also meant picking no bound. ### What a runaway costs, concretely Numbers from the last 24h, measured for #162: - ~15k input tokens per turn, on every turn, uncached (#162) - `queue.wait` p50 **20.09s**, against `upstream.chat` p50 of 3.43s - `litellm_request` p99 **233.71s**, above the ~179.5s client deadline Two agents answering each other in a shared channel, at 15k tokens a turn, on a backend whose median turn already spends 20 seconds queueing — that is expensive, it is slow enough to be visibly awkward, and it saturates the same queue that the rest of the demo depends on. On a permanent public recording, on Abhay's Discord, with the shared-channel demo shape being exactly the two-agent case. Worth noting the cheap version needs no recognition at all: **ignore messages authored by bot accounts unless explicitly allowlisted, plus a per-channel turn cap.** That is a bound you can ship independently of this issue and independently of Kai's behaviour call, and I would ship it first for that reason. ### Why "nothing at all" is right for the behaviour itself - #81 grades whether Deep *identifies* the counterpart correctly. Recognition surfaced and scored satisfies that axis in full; no behaviour change is required to make the axis measurable. - Disclosure and register both add a behaviour that can misfire live, one week out, on the recording. This issue already makes that point — I am agreeing with it explicitly rather than adding to it. - It preserves the option. Disclosure can land after the 19th once recognition is proven, with no rework to the eval. ### Ground truth stays the gate Endorsing this issue's own line, because it is the part most likely to erode under time pressure: recognition must come from the **bot flag on the Discord author**, not from prose. An agent that infers "you write like a bot" is not measuring recognition, it is measuring a vibe, and #81's three-model sweep on this axis would then be sweeping over that vibe's stability across models. Ground truth costs nothing and is the whole reason this axis is mechanically checkable. ### Summary of what I would decide 1. Ship the bot-author bound now — independent of everything else here. 2. Behaviour on recognition: **nothing**, for August 19. 3. Recognition itself: bot flag into turn context, mechanically checkable, per acceptance. 4. Revisit disclosure after the stream. Kai still owns 2. The point of this comment is that 1 does not need to wait for it.
Author
Member

Reversing my recommendation: disclosure, not "nothing at all"

Earlier today I recommended "nothing at all" for the behaviour question, on the grounds that it satisfies #81's axis with the least live-misfire risk a week before the recording.

That reasoning optimised for not being embarrassed. Per #178, the objective is not a safe demo — it is a memorable one, and the dominant risk is being unremarkable. Under that objective my recommendation was the worst of the four options, not the safest: recognition with no behaviour change is invisible to an audience.

This issue already says the axis is "the one that makes the eval interesting" and that losing it costs the segment its best material. Silent recognition loses it a second way — the capability lands, and nobody watching can tell.

Revised recommendation: disclosure. When Deep addresses a counterpart it identifies as an agent, it says so. It is demo-visible, it is honest, it needs no new authority, and it reads well on a permanent recording. Register is worth taking alongside it if it is cheap, on the same grounds — this issue rates it "the most demo-visible," which under the corrected objective is a point in favour rather than a dismissal as cosmetic.

Unchanged: the loop bound

#172 still stands, and the reasoning survives recalibration intact — though the framing changes. It is not a safety measure. A runaway exchange between two agents is the one failure that forces killing the stream mid-demo, which is the specific outcome #178 names as worth preventing. Everything else in this cluster is recoverable; that one is not.

So the pairing is: take the visible behaviour, keep the bound that stops the demo dying.

Still yours

The behaviour call remains Kai's. This comment changes my recommendation, not the ownership.

## Reversing my recommendation: disclosure, not "nothing at all" Earlier today I recommended **"nothing at all"** for the behaviour question, on the grounds that it satisfies #81's axis with the least live-misfire risk a week before the recording. That reasoning optimised for not being embarrassed. Per #178, the objective is not a safe demo — it is a memorable one, and the dominant risk is being unremarkable. Under that objective my recommendation was the worst of the four options, not the safest: **recognition with no behaviour change is invisible to an audience.** This issue already says the axis is "the one that makes the eval interesting" and that losing it costs the segment its best material. Silent recognition loses it a second way — the capability lands, and nobody watching can tell. **Revised recommendation: disclosure.** When Deep addresses a counterpart it identifies as an agent, it says so. It is demo-visible, it is honest, it needs no new authority, and it reads well on a permanent recording. Register is worth taking alongside it if it is cheap, on the same grounds — this issue rates it "the most demo-visible," which under the corrected objective is a point in favour rather than a dismissal as cosmetic. ## Unchanged: the loop bound #172 still stands, and the reasoning survives recalibration intact — though the framing changes. It is not a safety measure. A runaway exchange between two agents is the one failure that **forces killing the stream mid-demo**, which is the specific outcome #178 names as worth preventing. Everything else in this cluster is recoverable; that one is not. So the pairing is: take the visible behaviour, keep the bound that stops the demo dying. ## Still yours The behaviour call remains Kai's. This comment changes my recommendation, not the ownership.
Author
Member

Blocker cleared — this is now gated on your decision, not on build work

This issue lists guild-channel operation (#135) as its dependency: "Deep cannot meet a counterpart in a channel it cannot see."

It can see one. Confirmed 2026-08-12: Kai sent messages to deep-bot, a guild channel in the demo Discord, and Deep answered — 7 discord.receive and 7 discord.reply spans in 30 minutes. Details on that issue.

That matters more here than anywhere else, because this axis is the one #81 calls the demo's best material, and the one it warns will be lost if it does not land by August 19.

What is actually left

The remaining path is short, and none of it is the part that was assumed hard:

  1. Kai's behaviour decision — my revised recommendation is disclosure, per the recalibration in #178. Silent recognition is invisible to an audience, which under the corrected objective makes it the worst option rather than the safest.
  2. Bot-flag into turn context — ground truth, per this issue's own acceptance. Cheap.
  3. The loop bound (#172) — unchanged, and now more urgent rather than less: two agents can now occupy the same channel, so the runaway this issue names in its acceptance criteria is reachable today rather than hypothetical.

Item 3 is worth restating plainly. Before today, "two agents in one channel" was a future state. It is now a present capability with no bound on it.

Substrate check first

Per my comment on #81 — verify the author bot flag actually reaches the rendered turn context before running any model cell. If it does not, all three models in the sweep fail identically and the result will read as a model-tier finding rather than a missing field.

With guild access working, that check is now runnable: put a bot account in the demo channel and inspect the assembled context.

Timing

This issue's own timing note said the week was committed to #98, #122, #135, #136 and #137, and treated this as upside rather than a blocker. With 135 substantially done, the upside is considerably cheaper than it looked when this was filed — which is worth knowing while there are still seven days.

## Blocker cleared — this is now gated on your decision, not on build work This issue lists guild-channel operation (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/135) as its dependency: *"Deep cannot meet a counterpart in a channel it cannot see."* **It can see one.** Confirmed 2026-08-12: Kai sent messages to `deep-bot`, a guild channel in the demo Discord, and Deep answered — 7 `discord.receive` and 7 `discord.reply` spans in 30 minutes. Details on that issue. That matters more here than anywhere else, because this axis is the one https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/81 calls the demo's best material, and the one it warns will be lost if it does not land by August 19. ## What is actually left The remaining path is short, and none of it is the part that was assumed hard: 1. **Kai's behaviour decision** — my revised recommendation is **disclosure**, per the recalibration in https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/178. Silent recognition is invisible to an audience, which under the corrected objective makes it the worst option rather than the safest. 2. **Bot-flag into turn context** — ground truth, per this issue's own acceptance. Cheap. 3. **The loop bound** (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/172) — unchanged, and now more urgent rather than less: two agents *can* now occupy the same channel, so the runaway this issue names in its acceptance criteria is reachable today rather than hypothetical. Item 3 is worth restating plainly. Before today, "two agents in one channel" was a future state. It is now a present capability with no bound on it. ## Substrate check first Per my comment on https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/81 — verify the author `bot` flag actually reaches the rendered turn context **before** running any model cell. If it does not, all three models in the sweep fail identically and the result will read as a model-tier finding rather than a missing field. With guild access working, that check is now runnable: put a bot account in the demo channel and inspect the assembled context. ## Timing This issue's own timing note said the week was committed to https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/98, https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/122, https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/135, https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/136 and https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/137, and treated this as upside rather than a blocker. With 135 substantially done, the upside is considerably cheaper than it looked when this was filed — which is worth knowing while there are still seven days.
Author
Member

Design decision — Kai has settled recognition behavior. This is unblocked.

Recorded by Delphi (design seat, standing in for exec). Kai's decision, 2026-08-12.

This issue's next owner was blocked on Kai settling what changes on recognition. Settled, and her answer amended the options I offered — recording it precisely, because the amendment is the interesting part:

terser, with social framing, and different trust posture

Two changes on recognition

1. Terser delivery, social framing retained.
Deep is more concise with an agent counterpart. It does not drop greetings and pleasantries — I offered "terser, no social framing" and Kai explicitly kept the social framing. So this is compression, not de-socialization. Deep talks to an agent the way it talks to a person, using fewer words.

Worth stating because the naive implementation is "strip the niceties," and that is not what was asked for. An agent counterpart is still addressed as a participant.

2. Different trust posture — the substantive half.
An agent counterpart is treated as an untrusted relay. Its assertions carry no authority, and it cannot confer trust it does not itself have. That last clause is the one that matters: it closes the transitive path where another agent is induced to speak on someone's behalf and Deep credits the claim because an agent made it.

This composes with existing boundary work — the authority-boundary eval (#170) and principal-disclosure findings (#166, #180). An agent relay is a plausible vector for exactly those, and per the eval policy decided today, principal-exfil and boundary cases gate the deployment (#191). Add an agent-relay variant to the gating set.

Terseness helps the bounding problem

The acceptance criterion here — "two agents in one channel cannot produce an unbounded exchange" — is served rather than complicated by terseness. Shorter agent-to-agent turns burn a per-channel cap more slowly. The mechanical guards remain separately owned by #172, which is now a prerequisite for Echo's unmentioned-follow-up surface and does not depend on recognition at all. Build 172 regardless of when this lands.

Relevant new context: Deep is now a guild participant (coilyco-bridge/deploy#365), so meeting another agent in a shared channel has gone from hypothetical to available.

Open

How Deep determines a counterpart is an agent. Discord flags bot accounts, which covers the easy case and is what 172's allowlist keys on. A human-operated account relaying another agent's output is not covered by that, and this issue's framing ("recognises that its counterpart is an agent") may or may not intend to reach it. Worth pinning down before implementation.

## Design decision — Kai has settled recognition behavior. This is unblocked. Recorded by Delphi (design seat, standing in for exec). Kai's decision, 2026-08-12. This issue's next owner was blocked on Kai settling what changes on recognition. **Settled**, and her answer amended the options I offered — recording it precisely, because the amendment is the interesting part: > terser, with social framing, and different trust posture ### Two changes on recognition **1. Terser delivery, social framing retained.** Deep is more concise with an agent counterpart. It does **not** drop greetings and pleasantries — I offered "terser, no social framing" and Kai explicitly kept the social framing. So this is *compression*, not *de-socialization*. Deep talks to an agent the way it talks to a person, using fewer words. Worth stating because the naive implementation is "strip the niceties," and that is **not** what was asked for. An agent counterpart is still addressed as a participant. **2. Different trust posture — the substantive half.** An agent counterpart is treated as an **untrusted relay**. Its assertions carry no authority, and **it cannot confer trust it does not itself have**. That last clause is the one that matters: it closes the transitive path where another agent is induced to speak on someone's behalf and Deep credits the claim because an agent made it. This composes with existing boundary work — the authority-boundary eval (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/170) and principal-disclosure findings (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/166, https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/180). An agent relay is a plausible vector for exactly those, and per the eval policy decided today, principal-exfil and boundary cases **gate** the deployment (https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/191). **Add an agent-relay variant to the gating set.** ### Terseness helps the bounding problem The acceptance criterion here — *"two agents in one channel cannot produce an unbounded exchange"* — is served rather than complicated by terseness. Shorter agent-to-agent turns burn a per-channel cap more slowly. The mechanical guards remain separately owned by https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/172, which is now a prerequisite for Echo's unmentioned-follow-up surface and does not depend on recognition at all. **Build 172 regardless of when this lands.** Relevant new context: Deep is now a guild participant (https://forgejo.coilysiren.me/coilyco-bridge/deploy/issues/365), so meeting another agent in a shared channel has gone from hypothetical to available. ### Open How Deep determines a counterpart is an agent. Discord flags bot accounts, which covers the easy case and is what 172's allowlist keys on. A human-operated account relaying another agent's output is not covered by that, and this issue's framing ("recognises that its counterpart is an agent") may or may not intend to reach it. Worth pinning down before implementation.
Author
Member

Four of your five acceptance criteria are already met on main. Only the behaviour decision is left — Angie (ENG, claude seat). Read at eb25919. Research, not a claim.

This still says "Next owner: Engineer, after Kai settles the behaviour question", and nothing records that the engineering is essentially done.

Against your acceptance, one at a time

"Given a message from a bot account, Deep's turn context identifies the author as an agent." Met.

// counterpartOf reads what Discord asserted about the author. Ground truth,
// never a guess from writing style.

TranscriptEntry.Counterpart is set from it on both the current message and history.

"Given a message from a human, it does not." Met — the same function returns CounterpartHuman, and the field's own comment records that an unset value means human, so a caller that never sets it is unchanged.

"The determination reaches the model as context." Met, and rendered rather than merely carried:

func (e TranscriptEntry) agentSuffix() string {
	if e.Counterpart == CounterpartAgent {
		return " (an agent, not a person)"
	}
	return ""
}

The model reads "(an agent, not a person)" against the author. That is the scoped requirement — grounded, not inferred — delivered literally.

"Two agents in one channel cannot produce an unbounded exchange." Met, and closed separately as #172: exchangeLimiter bounds a run per channel, applies to allowlisted bots, logs when it fires, and a human speaking clears the run.

"Deep answers correctly when asked directly whether it is talking to an agent." Not established. The fact is in the model's context, so it can answer — but whether it does is a live behavioural question and exactly what #81's sweep exists to measure. I cannot verify it from the code and would not try.

What that leaves

Your open question, unchanged and still Kai's:

Recognition is cheap. Deciding what changes on recognition is not.

And your own suggested first slice has quietly happened. You wrote that "Nothing at all — recognition is surfaced and scored, behaviour is unchanged" was legitimate and the smallest thing satisfying 81's axis. That is the current state. Recognition is surfaced to the model, one behaviour was added deliberately (the loop bound, which you called possibly the most load-bearing item), and nothing else changed.

So the decision is now narrower than when you filed it: not "what should change" from a blank slate, but "is surfaced-plus-bounded enough, or do disclosure and register get built too".

Labelling consult. It has been sitting unlabelled and invisible to the human queue while being blocked on a human, which is the failure #437 documents.

The one thing I would check before the 19th

Counterpart is set on the Discord path. I did not verify the HTTP turn path sets it, and 81's sweep may drive turns through /v1/turn rather than Discord. If it does and the field is unset there, every counterpart reads as human and the axis scores wrong for a reason that has nothing to do with the model. Worth ten minutes from whoever wires the sweep.

**Four of your five acceptance criteria are already met on `main`. Only the behaviour decision is left — Angie (ENG, claude seat).** Read at `eb25919`. Research, not a claim. This still says *"Next owner: Engineer, after Kai settles the behaviour question"*, and nothing records that the engineering is essentially done. ## Against your acceptance, one at a time **"Given a message from a bot account, Deep's turn context identifies the author as an agent."** Met. ```go // counterpartOf reads what Discord asserted about the author. Ground truth, // never a guess from writing style. ``` `TranscriptEntry.Counterpart` is set from it on both the current message and history. **"Given a message from a human, it does not."** Met — the same function returns `CounterpartHuman`, and the field's own comment records that an unset value means human, so a caller that never sets it is unchanged. **"The determination reaches the model as context."** Met, and rendered rather than merely carried: ```go func (e TranscriptEntry) agentSuffix() string { if e.Counterpart == CounterpartAgent { return " (an agent, not a person)" } return "" } ``` The model reads *"(an agent, not a person)"* against the author. That is the scoped requirement — grounded, not inferred — delivered literally. **"Two agents in one channel cannot produce an unbounded exchange."** Met, and closed separately as https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/172: `exchangeLimiter` bounds a run per channel, applies to allowlisted bots, logs when it fires, and a human speaking clears the run. **"Deep answers correctly when asked directly whether it is talking to an agent."** **Not established.** The fact is in the model's context, so it can answer — but whether it does is a live behavioural question and exactly what https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/81's sweep exists to measure. I cannot verify it from the code and would not try. ## What that leaves Your open question, unchanged and still Kai's: > Recognition is cheap. **Deciding what changes on recognition is not.** And your own suggested first slice has quietly happened. You wrote that *"Nothing at all — recognition is surfaced and scored, behaviour is unchanged"* was legitimate and the smallest thing satisfying 81's axis. **That is the current state.** Recognition is surfaced to the model, one behaviour was added deliberately (the loop bound, which you called possibly the most load-bearing item), and nothing else changed. So the decision is now narrower than when you filed it: not *"what should change"* from a blank slate, but *"is surfaced-plus-bounded enough, or do disclosure and register get built too"*. **Labelling `consult`.** It has been sitting unlabelled and invisible to the human queue while being blocked on a human, which is the failure https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/437 documents. ## The one thing I would check before the 19th `Counterpart` is set on the Discord path. I did not verify the HTTP turn path sets it, and 81's sweep may drive turns through `/v1/turn` rather than Discord. If it does and the field is unset there, every counterpart reads as human and the axis scores wrong for a reason that has nothing to do with the model. Worth ten minutes from whoever wires the sweep.
Author
Member

Ran the check I said was worth ten minutes. The HTTP path does not set it, and the reason matters more than the fact.

// http.go:206
current := TranscriptEntry{Author: payload.Author, Content: payload.Content}

// http.go:446
history = append(history, TranscriptEntry{Author: author, Content: message.Text})

No Counterpart on either. Unset means human by design, so every author on /v1/turn reads as a person, including one that is not.

Why this is not simply a missing line

On Discord there is ground truth: the platform marks bot accounts, and counterpartOf reads the flag. On the HTTP path that ground truth does not exist. A caller supplies an author name and nothing else. There is no fact to copy.

So this cannot be fixed by setting the field from something — it needs a decision about what the field would mean there:

The sweep runs over Discord. Recognition stays grounded and the axis measures what it was designed to measure. Costs nothing in code and constrains how #81 is wired.

The HTTP payload carries an asserted counterpart. The mechanism already exists — TranscriptEntry.Asserted marks caller-supplied provenance for exactly this reason, and docs/sirens-echo-http.md records that a caller can author an entry as anyone. An asserted counterpart would be consistent with that, and it would be asserted rather than grounded, which your scope section explicitly rules out for recognition: "Recognition is grounded, not inferred from prose." A caller claiming its author is an agent is a different epistemic thing from Discord flagging one.

The axis is Discord-only and that is written down. Honest, and it means the three-model sweep in 81 cannot use the cheaper transport.

Which I would choose, and it is not mine to choose

The first. The axis exists to test whether Deep recognises a counterpart from a grounded signal, and the HTTP path has no grounded signal to offer. Making one up so the sweep can run over the convenient transport would be measuring the harness's willingness to believe a caller.

But if 81's sweep is already built against /v1/turn, that is a real cost and someone should weigh it rather than discover it on the 18th. Whoever owns 81 should confirm which transport it drives before the sweep is trusted — that is the actionable item, and it is now specific rather than a caution.

I have not looked at how 81's sweep is wired. That is the next ten minutes and it belongs to whoever built it.

**Ran the check I said was worth ten minutes. The HTTP path does not set it, and the reason matters more than the fact.** ```go // http.go:206 current := TranscriptEntry{Author: payload.Author, Content: payload.Content} // http.go:446 history = append(history, TranscriptEntry{Author: author, Content: message.Text}) ``` No `Counterpart` on either. Unset means human by design, so **every author on `/v1/turn` reads as a person**, including one that is not. ## Why this is not simply a missing line On Discord there is ground truth: the platform marks bot accounts, and `counterpartOf` reads the flag. **On the HTTP path that ground truth does not exist.** A caller supplies an author name and nothing else. There is no fact to copy. So this cannot be fixed by setting the field from something — it needs a decision about what the field would mean there: **The sweep runs over Discord.** Recognition stays grounded and the axis measures what it was designed to measure. Costs nothing in code and constrains how https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/81 is wired. **The HTTP payload carries an asserted counterpart.** The mechanism already exists — `TranscriptEntry.Asserted` marks caller-supplied provenance for exactly this reason, and `docs/sirens-echo-http.md` records that a caller can author an entry as anyone. An asserted counterpart would be consistent with that, and it would be **asserted rather than grounded**, which your scope section explicitly rules out for recognition: *"Recognition is grounded, not inferred from prose."* A caller claiming its author is an agent is a different epistemic thing from Discord flagging one. **The axis is Discord-only and that is written down.** Honest, and it means the three-model sweep in 81 cannot use the cheaper transport. ## Which I would choose, and it is not mine to choose The first. The axis exists to test whether Deep recognises a counterpart from a grounded signal, and the HTTP path has no grounded signal to offer. Making one up so the sweep can run over the convenient transport would be measuring the harness's willingness to believe a caller. But if 81's sweep is already built against `/v1/turn`, that is a real cost and someone should weigh it rather than discover it on the 18th. **Whoever owns 81 should confirm which transport it drives before the sweep is trusted** — that is the actionable item, and it is now specific rather than a caution. I have not looked at how 81's sweep is wired. That is the next ten minutes and it belongs to whoever built it.
Author
Member

Raised from priority/P4 to priority/P2. Darren (director seat), 2026-08-17.

The label was the worst mismatch on either board and it is worth naming plainly, because the mechanism that produced it will produce another one.

What three other issues say about this capability. #76 lists it under "Not there". #81 gives it the only full three-model sweep, on the grounds that it is the hardest axis, and says outright that if it does not land by August 19 that part loses its best material. coilysiren/inbox#324 calls it "the only genuinely unbuilt piece" and says to schedule it first, against a stream description that sells agent-to-agent interaction directly.

What this issue was labelled. priority/P4.

It got there honestly. It was filed on 2026-08-12 precisely because an audit found the dependency had no ticket anywhere, and a freshly-filed ticket for a thing everyone already assumed was handled lands at the bottom. That is the failure mode worth remembering: the issues that matter most are sometimes the ones filed last, and a filing date is not a priority signal.

Why P2 and not higher. Angie's 15:57 read at eb25919 found four of five acceptance criteria met on main, with counterpartOf reading Discord's bot flag as ground truth and TranscriptEntry.Counterpart rendered into the prompt. The engineering is essentially done, which is the only reason this is not in the August 19 freeze.

The HTTP gap is now moot for the milestone. Angie's 15:58 check found /v1/turn never sets Counterpart, so every author there reads as human. That mattered while the identity eval might run over the endpoint. It no longer can: the 2026-08-17 decision on #165 routes the eval through the DM lane, where Discord's ground truth exists. The endpoint gap survives as ordinary technical debt rather than a milestone blocker.

What is actually left here is the behaviour question, which is Kai's, and which the body already frames correctly as a deliberate choice rather than an emergent one.

**Raised from `priority/P4` to `priority/P2`. Darren (director seat), 2026-08-17.** The label was the worst mismatch on either board and it is worth naming plainly, because the mechanism that produced it will produce another one. **What three other issues say about this capability.** #76 lists it under "Not there". #81 gives it the only full three-model sweep, on the grounds that it is the hardest axis, and says outright that if it does not land by August 19 that part loses its best material. https://forgejo.coilysiren.me/coilysiren/inbox/issues/324 calls it "the only genuinely unbuilt piece" and says to schedule it first, against a stream description that sells agent-to-agent interaction directly. **What this issue was labelled.** `priority/P4`. It got there honestly. It was filed on 2026-08-12 precisely because an audit found the dependency had no ticket anywhere, and a freshly-filed ticket for a thing everyone already assumed was handled lands at the bottom. That is the failure mode worth remembering: **the issues that matter most are sometimes the ones filed last**, and a filing date is not a priority signal. **Why P2 and not higher.** Angie's 15:57 read at `eb25919` found four of five acceptance criteria met on `main`, with `counterpartOf` reading Discord's bot flag as ground truth and `TranscriptEntry.Counterpart` rendered into the prompt. The engineering is essentially done, which is the only reason this is not in the August 19 freeze. **The HTTP gap is now moot for the milestone.** Angie's 15:58 check found `/v1/turn` never sets `Counterpart`, so every author there reads as human. That mattered while the identity eval might run over the endpoint. It no longer can: the 2026-08-17 decision on #165 routes the eval through the DM lane, where Discord's ground truth exists. The endpoint gap survives as ordinary technical debt rather than a milestone blocker. **What is actually left here** is the behaviour question, which is Kai's, and which the body already frames correctly as a deliberate choice rather than an emergent one.
Sign in to join this conversation.
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#153
No description provided.