Skip to content

fix(tune-out): enforce diversion across live delivery and recovery - #201

Closed
antra-tess wants to merge 2 commits into
mainfrom
fix/tuneout-live-integration
Closed

antra-tess wants to merge 2 commits into
mainfrom
fix/tuneout-live-integration

Conversation

@antra-tess

@antra-tess antra-tess commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Tune-out could leak diverted traffic into a resident's live tool continuation, publish subconscious prose despite allowChannelSpeech: false, and wake the resident through delayed gate events. Cancellation could omit pending messages, and restart recovery could leave cadence and duration timers unarmed when a connector registered late. These were reproduced during review before the first live trial (related to #77).

Changes

  • Share the resident visibility predicate between compiled context and live continuations. Store diverted originals promptly so the subconscious can read them while the resident is busy; preserve quiesce and store-surgery write barriers.
  • Include deferred primary messages in cancellation backlogs, deduplicating stored writes before applying the cap. Prevent newer diverted writes from overtaking older queued originals after resume, preserving receipt order before and after flush.
  • Route debounced and buffered tune-out events by their original epoch. Preserve ordinary pre-epoch wakes and conversation-fork routing; neither may be reassigned to a tune-out epoch. Preserve ordinary events in mixed batches and consume an ended epoch's stale wakes without charging a newer epoch.
  • Disable subconscious prose publication, including >> envelopes. Channel speech remains available through the configuration-gated speak_in_channel tool.
  • Recover active epochs from durable desired state, independent of connector registration; cancel overdue epochs at startup.
  • Add 21 integration regression tests and extend the MCPL fixture for delayed registration and multiple channels.

No connectome-host changes or companion PR are required.

Tests

Final head: 484b990.

  • npm run build and npm run typecheck: passed.
  • Full compiled suite, node --test --test-force-exit --test-concurrency=4 dist/test/*.test.js: 1,028 passed, 0 failed, 4 skipped.
  • bun test test/tune-out-review-regressions.test.ts: 21 passed, 0 failed.
  • The seven cases covering pre-epoch ordinary wakes, newly bound forks, and backlog ordering/caps before and after flush all failed on b96a1dc and pass with the follow-up.
  • Connectome-host subconscious-recipe validation, unchanged by this PR: 9 passed, 0 failed in the original review.

The initial default-concurrency full run encountered a 1,000ms RPC timeout in startup globally gates push/event with discord-first config. That test passed in isolation, and the complete lower-concurrency run above passed. Integration tests use real Chronicle stores and a local MCPL fixture with mocked inference.

Not verified

Not deployed or exercised against a live model provider or production connector.


  • Changelog fragment added: changelog.d/fix-tuneout-live-integration.fixed.md

🤖 Generated with Codex.

Share resident visibility across compiled and live context, keep diverted originals available during resident work, and include deferred writes in cancellation backlogs. Route delayed gate events through epoch-aware tuneout handling, disable subconscious prose publication, and recover timers from durable epochs.

Co-Authored-By: Codex (GPT-6) <noreply@openai.com>
@greptile-apps

greptile-apps Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 3/5 Tier: apex

[Medium impact] The PR changes the bounded tune-out workflow across channel intake, resident context, and restart recovery.

Fix the two delayed-wake routes before merging.

Findings

  1. P1 Fork wakes reach everyone ▶
  2. P1 Wake and message disagree ▶
Fix with agent prompt
### Issue 1
src/framework.ts:1587-1588
With `conversations` enabled, returning here sends the delayed wake through `EventGate.deliverEvents`. That writes the notice to the primary and wakes every non-subconscious agent. When an unbound tuned-out channel creates a fork, the template and unrelated forks wake too, even though only the new fork received the message. Target the delayed wake and notice to that fork instead of using the broadcast path.

### Issue 2
src/framework.ts:1594
`epochAtArrival` is read before the message enters the queue, but `handleMcplChannelIncoming` chooses its stamp later. If a live resident calls `tune_out` before that queued message is handled, this return leaves the delayed wake ordinary while ingestion stamps and hides the original. The resident gets a wake for input it cannot see, while an addressed message misses its subconscious wake. Use one routing decision for storage and delayed delivery without reclaiming already-stored ordinary input.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR tightens tune-out delivery, cancellation backlogs, private subconscious speech, and restart recovery.

  • Diverted messages stay out of resident turns and remain available to the subconscious.
  • Cancellation includes queued diverted messages in arrival order.
  • Delayed channel wakes keep the tune-out epoch they arrived under.
  • Subconscious prose stays private while configured channel speech still works.
  • Active tune-outs recover their timers before channels register.

Reviews (2) · Last reviewed commit: "fix(tune-out): preserve deferred wake ow..." · Reviewed by Greptile

Comment thread src/framework.ts Resolved
Comment thread src/framework.ts Resolved
Comment thread src/framework.ts Resolved
Keep ordinary pre-epoch wakes on the resident path and leave conversation-fork wakes to conversation routing. Queue newer diverted writes behind older deferred originals so capped cancellation preserves receipt order before and after flush.

Co-Authored-By: Codex (GPT-6) <noreply@openai.com>
Comment thread src/framework.ts
Comment on lines +1587 to +1588
if (!framework.subconsciousAgentName || framework.conversationRouter
|| info.eventType !== 'mcpl:channel-incoming') return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Fork wakes reach everyone

With conversations enabled, returning here sends the delayed wake through EventGate.deliverEvents. That writes the notice to the primary and wakes every non-subconscious agent. When an unbound tuned-out channel creates a fork, the template and unrelated forks wake too, even though only the new fork received the message. Target the delayed wake and notice to that fork instead of using the broadcast path.

Knowledge Base Used: MCPL conversation and inference routing

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/framework.ts
Line: 1587-1588

Comment:
**Fork wakes reach everyone**

With `conversations` enabled, returning here sends the delayed wake through `EventGate.deliverEvents`. That writes the notice to the primary and wakes every non-subconscious agent. When an unbound tuned-out channel creates a fork, the template and unrelated forks wake too, even though only the new fork received the message. Target the delayed wake and notice to that fork instead of using the broadcast path.

**Knowledge Base Used:** [MCPL conversation and inference routing](https://app.greptile.com/anima-labs/-/custom-context/knowledge-base/anima-research/agent-framework/-/docs/mcpl-conversation-and-inference.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment thread src/framework.ts
// Ordinary input remains resident-visible. A later tune-out must
// not retroactively claim its wake, acknowledge it as suppressed,
// or debit the new epoch's budget.
if (!epochAtArrival) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Wake and message disagree

epochAtArrival is read before the message enters the queue, but handleMcplChannelIncoming chooses its stamp later. If a live resident calls tune_out before that queued message is handled, this return leaves the delayed wake ordinary while ingestion stamps and hides the original. The resident gets a wake for input it cannot see, while an addressed message misses its subconscious wake. Use one routing decision for storage and delayed delivery without reclaiming already-stored ordinary input.

Knowledge Base Used: Event gate pipeline

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/framework.ts
Line: 1594

Comment:
**Wake and message disagree**

`epochAtArrival` is read before the message enters the queue, but `handleMcplChannelIncoming` chooses its stamp later. If a live resident calls `tune_out` before that queued message is handled, this return leaves the delayed wake ordinary while ingestion stamps and hides the original. The resident gets a wake for input it cannot see, while an addressed message misses its subconscious wake. Use one routing decision for storage and delayed delivery without reclaiming already-stored ordinary input.

**Knowledge Base Used:** [Event gate pipeline](https://app.greptile.com/anima-labs/-/custom-context/knowledge-base/anima-research/agent-framework/-/docs/event-gates.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@nissa-seru

Copy link
Copy Markdown
Contributor

@antra-tess - closing this for housekeeping as I believe this is handled by #546 and #232; feel free to reopen if desired

@nissa-seru nissa-seru closed this Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

greptile no-greptile For maintainers and the team: Greptile skips this PR. Not for general use.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants