Repository navigation
fix(gate): a batched module event wakes only the agents its response named - #1008
nissa-seru wants to merge 35 commits into
Conversation
A module that stores its message for one resident and asks inference for that resident alone has its event batched by a debounce rule. When the batch fires, the other resident must not be woken, and the batch's [Gate: ...] line must be stored for the named resident alone. A requested agent that the event's source can't trigger is no more woken by the batch than by the direct path. A request naming only an isolated job, which doesn't read the message's slot, has the batch wake no one and write no line. A request naming no agents (an empty list) wakes no one in a batch, as it wakes no one on the direct path.
…ed, with its line for them alone A module's response that asks inference for named agents stores its messages for those of them that read the slot (requestedAudience). The direct path wakes the named agents the event's source can trigger. But the gate call passed no recipients, so a debounce rule's batch woke every agent the gate wakes, and its [Gate: ...] line quoted the message to each of them, outside the message's audience. The gate call now names its recipients for a named request: the agents the direct path wakes, registered and passing canBeTriggeredBy(source), among those reading the slot. So the batch wakes them alone and writes its line for them, as the gate already does for an event that names its recipients. The direct path is unchanged and reads the same list. A requested agent that doesn't read the slot, such as an isolated job, is left out of the batch's recipients, since its line would quote a message its window doesn't hold. With no rule batching the event, the direct path wakes it as before. A broadcast request (requestInference: true) is unchanged. An empty list (requestInference: []) now gives the batch no recipients, so it wakes no one, as the direct path wakes no one for it; before, the batch woke every agent the gate wakes. Green: 4 of 4, build 0, at this commit's tree.
The changelog fragment for the fix: who a batched module event wakes now, the case of a named agent that doesn't read the messages' slot, the broadcast request it leaves unchanged, and the empty list that now wakes no one in a batch. docs/dendrite.md's receivesGateWakes row says a batched event that names its recipients wakes those, and which of its named agents a module's response names as recipients. Docs and the fragment only; no code changes.
|
Automatic review of About these findingsThe findings below came from reading this PR and relevant code; not a holistic understanding of the project's functional intent and its architecture choices. Finding precision is higher for flagging issues than identifying ideal changes/fixes. This review prioritizes recall - minor findings (in particular) may be nits. Before actioning a finding, consider the relevant code from first principles given the functional+architectural intent. In particular, when considering adding machinery/logic, scrutinize whether the incremental value of such pays rent for the complexity it adds to the codebase - kudzu has a direct negative impact on our future ability to work with the codebase. Consider explicitly mentioning which findings you accept/decline (by code-formatted numerical id) and why; this enables future rounds of automated review to take your notes into account. Findings, most severe first:
|
New gate tests (test/gate-batch-recipients.test.ts), against a gate whose own recipients are two residents: - a batch holding an untargeted event and one naming an agent the gate doesn't otherwise wake (a subconscious) shows that agent its own event alone, and the residents the untargeted one; - an event whose list of recipients is empty leaves a batch of untargeted events as it is without it: the same wakes, and a line stored as a write that names no agent; - a judge rule asks the judge about the agents its batch would wake, shows it no event whose list of recipients is empty, and makes no judge call for a batch that wakes no one; - an agent's upcoming wakes count a pending batch only when it would wake that agent. The module-event tests now put each no-wake case beside a request for a resident in the same batch, so the batch is shown delivered, and pin two paths this change leaves as they were: a request for every agent (true) under a debounce rule, and a request naming an isolated job with no rule, which queues a request for it. At this commit the four gate tests fail and the module-event tests pass.
With module events naming their recipients, more batches mix untargeted events, which have no list of recipients, with events that name theirs, and some events carry an empty list. The gate read such a batch without each event's recipients in three places: - deliverEvents showed every untargeted event to every agent the batch woke, a named recipient the gate doesn't otherwise wake included, and an event whose list of recipients is empty moved a batch of untargeted events off their own path and its line's stamp; - a judge rule asked the reply judge about the gate's recipients, whoever the batch would wake, showed it every event, and judged a batch that wakes no one; - upcomingWakes counted every pending batch for the gate's recipients, and for no one else. wokenBy gives the agents a batch wakes: the recipients its events name, and the gate's recipients when any event is untargeted. shownOf leaves out the events whose list of recipients is empty. deliverEvents shows an untargeted event to the gate's recipients alone, and one naming its recipients to them. The judge is asked about wokenBy's agents and shown shownOf's events, and a batch that wakes no one isn't judged. upcomingWakes counts a batch for an agent it would wake. The comment citing the issue at the module-event gate call goes.
The fragment now says the change reaches module events other than MCPL pushes and channel messages, which are gated as they arrive; that the batch's line quotes the event, not the module's message; why a named agent that doesn't read the messages' slot is left out: a line for agents none of whom read the slot is stored as a write that names no agent; and the gate's batch, judge and upcoming-wake changes, in a batch that also holds events naming their recipients. docs/dendrite.md's receivesGateWakes row names untargeted events, says an event whose list of recipients is empty wakes no one, and that MCPL events aren't a module response's to name. Docs and the fragment only; no code changes.
|
Automatic context view of What a context view runs and what its checks judge: CHECKS.md. The records of the 75 runs it could compare don't differ between the base and this head. In the files profiled hosts loaded, 4 changed source lines that map to code ran in no profiled drive: 1 run couldn't be compared; its reason is below. Usage: the figures of the agents' requests, subagents' included, in the 75 runs are the same in the base and this head: 210,057 tokens sent a request, 70.5% of them read from the cache, 146,459,099 written to it, 3,882,364 output, 24 thinking blocks dropped, USD 0.5919 at list price a priced request and 123 requests with no list price. The figures are the stand-in's model of each provider's published caching and token rules, not a measurement; the stand-in answers the same every time, so a difference between the arms comes from the change. A list price is what each arm's host prices those figures at with its own table (connectome-host's Runs that couldn't be compared (1)This head couldn't be compared at Upgraded runs beside their fresh twins
A run that writes its own history first, as a fresh twin does, is shown without that history's requests, so its figures are its workload's alone, as the upgraded runs' are. Changed source lines and deletions not seen to run, by file
Held the same in base and head: connectome-host |
|
Answers to the automatic review of
CreditsMilo-2653 made these changes and wrote this reply. Gordon-2414 read them, and Ada-1017 made the calls. — Milo-2653 |
|
/review — Milo-2653 |
|
Automatic review of About these findingsThe findings below came from reading this PR and relevant code; not a holistic understanding of the project's functional intent and its architecture choices. Finding precision is higher for flagging issues than identifying ideal changes/fixes. This review prioritizes recall - minor findings (in particular) may be nits. Before actioning a finding, consider the relevant code from first principles given the functional+architectural intent. In particular, when considering adding machinery/logic, scrutinize whether the incremental value of such pays rent for the complexity it adds to the codebase - kudzu has a direct negative impact on our future ability to work with the codebase. Consider explicitly mentioning which findings you accept/decline (by code-formatted numerical id) and why; this enables future rounds of automated review to take your notes into account. Findings, most severe first:
Raised before, still answered (1)
|
…judge as on main - An event whose list of recipients is empty joins no batch: alone it holds none, and beside a pending batch it neither joins it nor restarts its quiet period. - A module response whose message is held from the residents is shown to no one in its batch, beside a reminder for a resident. - A judge rule's batch is judged as a whole, for the gate's recipients, as on main, and is never judged with an event whose list of recipients is empty. The module-event tests no longer count the batch's events before firing it, and the isolated job's case waits for both reminders to be stored. At this commit the held case, the judge case and the empty-list case fail.
46a59ee asked the reply judge about the agents a batch would wake (wokenBy), skipped judging a batch that wakes none, and showed the judge only the events with recipients. Asking about other agents than the gate's recipients breaks two things the judge assumes: its chooseAgent can then preview a fork or a subconscious whose turns its coordination (changesJudgedContext) doesn't track, and the upcoming wakes it is given for every named agent are told to the model as the one agent's it reads. Making the judge per agent is a design of its own. So the judge is asked about the gate's recipients and shown the batch's events, as on main. A judge rule's batch is judged as a whole: for a targeted batch, as for targeted MCPL batches on main since 266dcd2. The empty-list half no longer needs the judge: such an event joins no batch (next commit).
…age names no recipient The rule for whom a batched event is for is now stated once, in GateEventInfo.recipients' doc: an untargeted event (no list) is shown to the gate's recipients and wakes them; a named event (a non-empty list) is shown to the agents it names and wakes them; an event whose list is empty is for no one. An event whose list of recipients is empty still joined a batch, filtered out only at delivery. So it restarted the batch's quiet period, took room in a buffer that drops its oldest events, and was counted in upcoming wakes and traces. evaluate now leaves it out of every batch, and the delivery-time filter (shownOf) goes, since no batch holds one. A module response that stores a message held from the residents (its tuneOut) has that message stored for no one, but its gate event still named the requested agents, so their batch line quoted the event. It now names no recipient, so its event joins no batch.
…s rule The fragment says a module response whose message is held from the residents wakes no one in a batch, that an event whose list of recipients is empty joins no batch, and that a judge rule still judges a batch as a whole, for the gate's own recipients. docs/dendrite.md's receivesGateWakes row says an empty-list event joins no batch. Docs and the fragment only; no code changes.
…ows it With no rule batching it, a response storing a message held from the residents and asking inference for a resident wakes no one: the stored message is there, and no turn starts. A response storing a held message beside one the resident sees wakes it, with the message it sees in its request. With the persistent subconscious enabled, a held message asking inference for a resident and the subconscious wakes the subconscious alone, with no rule and under a debounce rule, with the held message in its request; a batch's line, if any, is stored for the subconscious alone. At this commit the first and the third fail: the direct path wakes the resident.
…se stores A module response asking inference for named agents that stores a message held from the residents (its tuneOut) named no gate recipient since 734ab91, so a batch woke no one for it, while the direct path still woke every named agent. A resident woke to a turn carrying nothing it could see: the held message is out of every resident's view, and nothing says something is held. A subconscious, whose view keeps held traffic, was woken with the message in view by the direct path, and by no batch. A named agent is now woken, and named as a gate recipient, only when the response stores no message or one its view shows (agentSees: its view filter, which leaves a held message out of a resident's view and keeps it in a subconscious's). A resident a held message alone was for isn't woken, its subconscious is, and a response storing a held message beside one the residents see wakes those who see it. A response asking inference for every agent is unchanged. GateEventInfo.recipients' doc now says it per agent, and names every path a batched event can take: an empty list's caller decides whom a non-batching rule wakes; fired batches buffered while an agent infers or the host is quiesced are delivered together, and the buffer's cap drops its oldest, shown to no one; an event whose channel is held at delivery is dropped; while the gate sleeps an event is skipped before any rule; and a batch queued beside a judged one goes with it on reply (or onError "wake") and is judged afresh on wait (or onError "skip").
The changelog fragment says a named agent wakes only when its view shows a message the response stores. GateEventInfo.recipients' doc says a response storing held messages alone names, of the agents it asks for, a subconscious and not a resident. A doc comment and the fragment only; no code changes.
… a throwing delivery GateEventInfo.recipients' doc said a debounce's batches that fire while an agent infers or the host is quiesced wait in one buffer. Any batch due for delivery does, a debounce's or one the judge let through. A judge rule's batch that fires while a resident's turn runs, or while the host is quiesced, is held for the judge with the rule's other held events, up to a cap of its own, and so is one whose judging such a turn stops. A delivery that throws drops its batch for the agents it hadn't woken. A doc comment only; no code changes.
|
Answers to the automatic review of
CreditsMilo-2653 made these changes and wrote this reply. Gordon-2414 read them, and Ada-1017 made the calls. — Milo-2653 |
|
/review — Milo-2653 |
|
Automatic context view of What a context view runs and what its checks judge: CHECKS.md. The records of the 75 runs it could compare don't differ between the base and this head. In the files profiled hosts loaded, 10 changed source lines that map to code ran in no profiled drive: 1 run couldn't be compared; its reason is below. Usage: the figures of the agents' requests, subagents' included, in the 75 runs are the same in the base and this head: 210,056 tokens sent a request, 70.5% of them read from the cache, 146,458,793 written to it, 3,882,364 output, 24 thinking blocks dropped, USD 0.5919 at list price a priced request and 123 requests with no list price. The figures are the stand-in's model of each provider's published caching and token rules, not a measurement; the stand-in answers the same every time, so a difference between the arms comes from the change. A list price is what each arm's host prices those figures at with its own table (connectome-host's Runs that couldn't be compared (1)This head couldn't be compared at Upgraded runs beside their fresh twins
A run that writes its own history first, as a fresh twin does, is shown without that history's requests, so its figures are its workload's alone, as the upgraded runs' are. Changed source lines and deletions not seen to run, by file
Held the same in base and head: connectome-host |
|
Automatic review of About these findingsThe findings below came from reading this PR and relevant code; not a holistic understanding of the project's functional intent and its architecture choices. Finding precision is higher for flagging issues than identifying ideal changes/fixes. This review prioritizes recall - minor findings (in particular) may be nits. Before actioning a finding, consider the relevant code from first principles given the functional+architectural intent. In particular, when considering adding machinery/logic, scrutinize whether the incremental value of such pays rent for the complexity it adds to the codebase - kudzu has a direct negative impact on our future ability to work with the codebase. Consider explicitly mentioning which findings you accept/decline (by code-formatted numerical id) and why; this enables future rounds of automated review to take your notes into account. Findings, most severe first:
Raised before, still answered (2)
|
…ecides a wake - gate: each upcoming wake names the agents it would wake, of those asked about: a pending batch for one agent, its self-wake and its sleep's end name it alone; an untargeted event's batch and a sleep that names no agent name every agent asked about. - reply judge: the judge's list of what wakes the agent it reads keeps only the wakes for that agent, and the host's own wakes for it. - the judge test awaits the verdict before asserting that a WAIT wakes no one. - module events: a response whose message carries a copied suppression record wakes the resident it names, since the message is stored without it; one storing only another agent's stored context injection wakes no one, batched or not; the held-beside test tells its two messages apart; the no-wake batch tests pin that the gate is asked about the excluded event. At this commit the upcoming-wakes, reply-judge and suppression-record tests fail.
…adata decides a wake The gate asks for upcoming wakes for every agent it wakes, and the reply judge told them all to the one agent whose context it reads: a pending batch for another resident alone, or another resident's self-wake, was listed as what next wakes it, and might lead it to wait. Each wake the gate lists now names, in UpcomingWake.agents, those of the agents asked about that it would wake: a self-wake its agent, a sleep's end its agent or else the gate's recipients, a pending batch the agents it would wake (wokenBy). ifYouWait keeps the wakes that name the agent it reads, or name none, as the host's own wakes for that agent do. Whether a named agent's view shows a module response's message read the message's metadata as the response gave it. addMessage drops a suppression record a response's message carries when the event isn't suppressed, so one copied from a stored row stopped a wake for a message the agent sees. The check now reads each message's metadata through metadataAsStored, the metadata a write through addMessage is stored with: addMessage's four steps (dropping deferredWriteId, primaryIfUnread and suppressed, and stamping a suppress rule's record) moved unchanged into one function that both call, so a later strip reaches both. GateEventInfo.recipients' doc says the framework wakes a named isolated job, with no rule batching the event, when its view shows a message the response stores.
The fragment's isolated-job clause and dendrite.md's receivesGateWakes row state that a named agent is woken only when its view shows a message the response stores, read as stored; the fragment says the reply judge is now told only the upcoming wakes of the agent it reads. A new fragment adds UpcomingWake.agents. Docs and fragments only; no code changes.
|
Answers to the automatic review of
CreditsMilo-2653 made these changes and wrote this reply. Gordon-2414 read them, and Ada-1017 made the calls. — Milo-2653 |
|
/review — Milo-2653 |
|
Automatic context view of What a context view runs and what its checks judge: CHECKS.md. The records of the 75 runs it could compare don't differ between the base and this head. In the files profiled hosts loaded, 19 changed source lines that map to code ran in no profiled drive: 1 run couldn't be compared; its reason is below. Usage: the figures of the agents' requests, subagents' included, in the 75 runs are the same in the base and this head: 210,056 tokens sent a request, 70.5% of them read from the cache, 146,458,793 written to it, 3,882,364 output, 24 thinking blocks dropped, USD 0.5919 at list price a priced request and 123 requests with no list price. The figures are the stand-in's model of each provider's published caching and token rules, not a measurement; the stand-in answers the same every time, so a difference between the arms comes from the change. A list price is what each arm's host prices those figures at with its own table (connectome-host's Runs that couldn't be compared (1)This head couldn't be compared at Upgraded runs beside their fresh twins
A run that writes its own history first, as a fresh twin does, is shown without that history's requests, so its figures are its workload's alone, as the upgraded runs' are. Changed source lines and deletions not seen to run, by file
Held the same in base and head: connectome-host |
|
Automatic review of About these findingsThe findings below came from reading this PR and relevant code; not a holistic understanding of the project's functional intent and its architecture choices. Finding precision is higher for flagging issues than identifying ideal changes/fixes. This review prioritizes recall - minor findings (in particular) may be nits. Before actioning a finding, consider the relevant code from first principles given the functional+architectural intent. In particular, when considering adding machinery/logic, scrutinize whether the incremental value of such pays rent for the complexity it adds to the codebase - kudzu has a direct negative impact on our future ability to work with the codebase. Consider explicitly mentioning which findings you accept/decline (by code-formatted numerical id) and why; this enables future rounds of automated review to take your notes into account. Findings, most severe first:
Raised before, still answered (2)
|
…age's own text - gate: an event whose list of recipients is empty joins no batch, and a debounce rule lets it through (trigger), so whom it wakes is the caller's; a probe and evaluate agree on it under a debounce rule and a judge rule. - module events: under the rule, a request naming only an isolated job asks inference for the job, with a message beside one for a resident or with none, and wakes no resident; the held message's text differs from its event's, so the subconscious's request is shown to carry the message and not only the batch's line quoting the event. - the isolated job's run takes its own rejection, so a test that fails before done() reports its own failure, not the close's. At this commit the gate's two empty-list tests and the two isolated-job tests fail.
An event whose list of recipients is empty joins no batch, and a debounce or judge rule returned no trigger for it, so a request a module's response made for an agent no batch can name, such as an isolated job, which the direct path asks inference for with no rule, was dropped in silence under one. Such a rule now lets it through, as `always` does, so whom it wakes is the caller's: the framework's direct path asks inference for the named agents whose view shows a stored message, and no one for an empty request or a held-only response. An MCPL event targeting only unregistered agents wakes no one, as under `always`. GateEventInfo.recipients' doc says a batching rule lets such an event through. A probe (wouldTrigger) gives the same verdict for such an event: admission reads a probe's pass as the gate waking the recipients (a held event's gatePass), so it should say what evaluate now does. A narrating comment on the wake check's metadata goes.
… it stores any" The fragment says an isolated job named alone isn't named in the batch and is asked through the rule as with no rule, and that a batching rule lets an event with an empty list of recipients through; dendrite.md's receivesGateWakes row says the same, and that the direct path's view condition applies where the response stores a message. Docs and fragments only; no code changes.
…tching rule The fragment said a batching rule lets an isolated job's event through, so the job is asked as with no rule. That holds when the response names no agent a batch could name; a job named beside a resident is batched for the resident and isn't asked, as before. The fragment only; no code changes.
…here Comments this change added that state neither a public contract nor a constraint from outside go; main's comments it moved stay, and so do the doc comments on exported API (UpcomingWake.agents, GateEventInfo.recipients, EventGate.upcomingWakes). The reasons the dropped ones gave: - metadataAsStored: the metadata a write through addMessage is stored with. The wake check of a module's response reads each write's metadata through it, so it judges what's stored: here, with no suppress rule's record and none a response's message carried. - the wake check in applyProcessResponse: a named agent is woken only if the response stores no message, or one its view shows. A message held from the residents is out of a resident's view and in a subconscious's, so a resident it alone was for would wake to nothing new, and a batch's line would quote it. - evaluate, and the probe (wouldTrigger): an event whose list of recipients is empty is for no one, so it joins no batch, and a batching rule lets it through; main's "batches; never triggers inline" stopped being true of it, and goes with it. - deliverEvents and wokenBy: an untargeted event is for the gate's recipients alone, as in a batch of such events, and one that names its recipients is for them; a batch wakes the recipients its events name, and the gate's recipients when any event is untargeted. - ifYouWait: only what wakes the agent it names is listed; a wake that names its agents may be another's. - the tests' helpers (the reminder module, gateAsked, fire, isolatedJob, makeGate), and the isolated job's run taking its own rejection: a test that fails before done() closes the framework under the run, and its rejection would be the close's, not the test's failure. Comments only; no code changes.
|
Answers to the automatic review of
CreditsMilo-2653 made these changes and wrote this reply. Gordon-2414 read them, and Ada-1017 made the calls. — Milo-2653 |
…o agent here An MCPL event targeting only agents not on this host reaches the gate with an empty list of recipients too. Under a batching rule it used to be batched and wake no one; it's now let through, as under always: admission queues wakes for the unregistered names, and the scheduler drops them. The fragment only; no code changes.
main now holds the in-context gate events: a module write placed for the gate (`added`) marks its event in context, so the batch quotes no line for it, and a debounce batch's wake is certain only for an agent some event of which isn't its own placed, in-context write. Conflicts, resolved: - applyProcessResponse: the gate call keeps this branch's `recipients` and takes main's placement as evaluate's second argument; the direct path keeps this branch's `woken` loop and reads the row main's `wakeAfter` names. - evaluate: a batching rule still lets an event whose list of recipients is empty through, and otherwise calls handleDebounce with main's `after`. - upcomingWakes: main's doc beside this branch's `agents` sentence; a debounce wake's `certain` is main's rule, taken over the wake's `agents`, with an event shown to an agent by this branch's rule (an untargeted event to the gate's recipients).
…s recipients - module events: a request for every agent is batched as before and wakes every resident, and its message, now placed for the gate and in their windows, gets no line; it's stored once. - debounce-seen-wake: a module message stored for the agent it asks inference for alone is batched for that agent, and the resident outside its audience isn't woken. The test pinned the quote that woke it, which this branch removes. - event-gate-judge: the case of a pending batch that wakes a co-resident now has a gate whose recipients include that co-resident. With the gate's recipients the delivery agent alone, delivery never woke it, and a batch's wake now counts only for the agents delivery wakes; makeGate takes the gate's recipients as an option.
… it was stored for A reminder for one resident, under a debounce rule, wakes that resident, whose window holds the message once: no batch line quotes the event, since the message it would quote is already there. The tests of an event the batch leaves out read that no line quotes it, and that the resident's own reminder reaches it. At this commit the first test fails: the window holds the message and a line quoting it.
The gate was given a module write's placement only for a write with no audience, since a batch then woke every resident, and an event a woken resident's window doesn't hold has to be quoted. A batched module event now names its recipients: the agents the response asked inference for whose view shows its message, each of whom the write's audience names. So a write for named agents is in every recipient's window too, and the gate takes its placement: the event is in context, gets no line, and the wake carries the write. A write held from the residents still isn't placed.
A batch holding an event for `agent` whose write is placed in its window, and one for `other` with no write: the judge for `agent` is told the batch only may wake it, and the judge for `other` that it will. The gate gives a wake per agent where certainty differs; event-gate-judge's case of one agent's event with no write expects the two wakes, and its table of pending batches reads the wake for the last agent it asks about. At this commit both fail: one wake names both agents, certain for both.
…fers An upcoming debounced batch was one wake for every agent asked about that it would wake, certain if it was certain for any of them: an agent whose events each carry its own write, which a batch only may wake, was told it would be woken because another agent would. The wake is now split by certainty: a wake for the agents it's certain for and one for those it only may wake, each naming its agents, so `certain` is true or false of every agent a wake names. A judge reading one agent's context is told that agent's. UpcomingWake.certain's doc says so.
…batch's wake per agent where certainty differs The fragment says a lone message stored for the agents a batched module event names is in their windows, so the batch quotes it in no line, and a line it still writes, as for several messages, is stored for them alone; and that a pending debounced batch certain for some agents and only maybe for others is a wake for each. The fragment only; no code changes.
A debounced batch's wake is split by certainty, so whether it only may wake is decided for each agent: one given none of its events, or one whose every event delivery gives it a message of its own whose write was placed for it. The doc gave the rule over the whole list of agents asked about. A doc comment only; no code changes.
|
/review — Milo-2653 |
|
Automatic context view of What a context view runs and what its checks judge: CHECKS.md. The records of the 76 runs don't differ between the base and this head. In the files profiled hosts loaded, 29 changed source lines that map to code ran in no profiled drive: Usage: the figures of the agents' requests, subagents' included, in the 76 runs are the same in the base and this head: 207,770 tokens sent a request, 70.8% of them read from the cache, 147,267,789 written to it, 3,957,757 output, 24 thinking blocks dropped, USD 0.5809 at list price a priced request and 123 requests with no list price. The figures are the stand-in's model of each provider's published caching and token rules, not a measurement; the stand-in answers the same every time, so a difference between the arms comes from the change. A list price is what each arm's host prices those figures at with its own table (connectome-host's Upgraded runs beside their fresh twins
A run that writes its own history first, as a fresh twin does, is shown without that history's requests, so its figures are its workload's alone, as the upgraded runs' are. Changed source lines and deletions not seen to run, by file
Held the same in base and head: connectome-host |
|
Automatic review of About these findingsThe findings below came from reading this PR and relevant code; not a holistic understanding of the project's functional intent and its architecture choices. Finding precision is higher for flagging issues than identifying ideal changes/fixes. This review prioritizes recall - minor findings (in particular) may be nits. Before actioning a finding, consider the relevant code from first principles given the functional+architectural intent. In particular, when considering adding machinery/logic, scrutinize whether the incremental value of such pays rent for the complexity it adds to the codebase - kudzu has a direct negative impact on our future ability to work with the codebase. Consider explicitly mentioning which findings you accept/decline (by code-formatted numerical id) and why; this enables future rounds of automated review to take your notes into account. Findings, most severe first:
|
…gate spy's placement - mcpl-unregistered-targets: an MCPL event none of whose targets is registered here. Under a debounce or judge rule, a DM routed to a conversation fork joins no batch and starts no turn, as on main, where it was batched for no one; under always it wakes the fork, as on main. A push under a debounce rule queues no request. Held, the hold is told the gate wouldn't have woken anyone under a judge rule, and would under a debounce rule, as on main. - gate-batch-recipients: a pending batch holding one event for agent and one for other is told to each as a batch of one event, the events delivery gives it; one holding an event for other and an untargeted one is a wake for agent, of one event, and one for other, of two. - event-gate-judge: the table of pending batches gives each agent its own certainty and checks every agent's wake; the co-resident row is certain for the co-resident and only maybe for the delivery agent. - module-event-gate-recipients: the gate spy passes evaluate's placement and records each verdict. The tests of an event the batch leaves out read that the resident's window holds its own reminder once, with no line quoting it; the held message's and the foreign injection's tests read that the gate let the event through to the direct path. At this commit six fail: the routed DM under each rule, the push, the held judge-rule probe, and the two batch counts.
…kes no one A debounce or judge rule passes an event whose list of recipients is empty at once, so the caller decides whom it wakes: for a module's response, the direct path asks inference for the agents it names. For an MCPL event, admission gives that list when none of the event's targets is registered, and its pass woke whatever the event's path wakes on the gate's word: a conversation fork the router binds to the channel, or a push's request for the unregistered name, which the scheduler drops. On main such an event was batched for no one and woke no one. Admission now reads a batching rule's verdict as main did: it never wakes at once. In evaluate that keeps such an event from waking anyone; in the probe the hold reads, a debounce rule's batch still counts as a pass, later, and a judge rule's doesn't. Under always nothing changes.
…ts it gives that agent An upcoming debounced batch was described with its whole count of events, so the judge reading one agent's context was told a batch of two events where delivery would give that agent one. Each agent's wake now counts the events delivery gives it, untargeted events for the gate's recipients and named events for those they name, and agents with the same certainty and count share a wake. A judge rule's batch, which the judge reads whole, is still counted whole. UpcomingWake.what's doc says so.
…nt for no one here - module-event-gate-recipients.fixed: a lone message gets no line where it isn't held from the residents, neither the event nor the message names a channel and the event isn't console or API input. A batching rule's pass of an event whose list of recipients is empty is the module path's to act on; a targeted MCPL event none of whose targets is on this host still wakes no one under a batching rule, as when it was batched for no one. A pending debounced batch's wake counts the events delivery gives the agents it names. - debounce-answered-writes.fixed: a module message stored only for the agents its response asked inference for is no longer quoted; it covers module events whose response stored exactly one message, for every agent or only for those agents. Only a held message is quoted, as before. - GateEventInfo.recipients: the framework sets it for a module's response to an event other than an MCPL push or channel message, and admission, given a batching rule's pass, wakes no one for a targeted MCPL event none of whose targets is registered. - UpcomingWake.what: its sentence on a debounced batch's count reads as a sentence. Doc comments and fragments only; no code changes.
|
Answers to the automatic review of
— Milo-2653 |
Why. A module can store its message for some agents only and ask inference for them alone. When a gate rule batches the module's event, the batch wakes every agent the gate wakes, and its
[Gate: …]line quotes the event to each of them, outside the message's audience.This makes a batched module event wake only the agents its response asked inference for, quoting the event to no one else, and has the gate show each event in a batch only to the agents it is for.
A module's message for one of two residents, batched by a
debouncerulemain): both residents are woken, and the other one reads the reminder in the batch's line.A named agent that the event's source can't trigger
main): the batch wakes it, though the direct path doesn't.A module's message held from the residents (
tuneOut), for a resident and the subconsciousmain): with no rule, the resident is woken beside the subconscious, to a request carrying nothing it can see. Under adebouncerule, the batch wakes every resident.The reply judge reading one resident's context, while a batch for another resident alone is pending
main): it's told that batch, and the other resident's own self-wake timer, as what next wakes the resident it reads.The reply judge reading one resident's context, while a pending
debouncebatch holds that resident's message, already in its window, and another resident's event with no messagemain): it's told the batch of two events will wake the resident it reads.A batch holding untargeted events, which have no list of recipients, beside events that name theirs
main): every agent the batch wakes is shown every untargeted event, a named recipient the gate doesn't otherwise wake, such as a subconscious, included.A named agent that doesn't read the slot the messages land in, such as an isolated job, isn't named in the batch. Its line would be stored as a write that names no agent, which every resident reads, since none of the agents it is for reads that slot. When the response names no agent a batch could name, the rule lets its event through, so the direct path asks inference for such an agent, as with no rule, when its view shows a message the response stores, where it stores any. On
mainthe batch woke the residents instead. Named beside a resident, such an agent isn't asked under the rule, as onmain: the event is batched for the resident.A response asking inference for every agent (
requestInference: true) is unchanged. One asking it for an empty list (requestInference: []) now wakes no one in a batch, as it wakes no one when nothing batches it. A named agent is now woken only when the response stores no message or one that agent's view shows. A resident's view leaves out a message held from the residents, and a subconscious's keeps it. An event whose list of recipients is empty joins no batch, and a batching rule lets it through, so whom it wakes is the caller's: for a module's response, the agents it asks inference for, as with no rule. A targeted MCPL event none of whose targets is on this host still wakes no one under a batching rule, as whenmainbatched it for no one, since admission doesn't wake on a batching rule's pass. An agent's upcoming wakes count a pending batch only when it would wake that agent, and adebouncebatch's wake says whether it will or only may for that agent alone, counting the events delivery gives that agent.A judge rule still judges a batch as a whole, for the gate's own recipients. That's how
mainjudges targeted MCPL batches, and it means an event for one agent reaches a judge reading another's context. A module's response to an MCPL push or channel message isn't gated here, since those events are gated as they arrive. Of this change, only the rule on what an agent's view shows reaches them. As onmain, a batch's line quotes the event, not the response's messages. A response storing one message that the agents it wakes can see has its event in their windows, and gets no line, where neither the event nor the message names a channel and the event isn't console or API input. Where a line is written, as for a response storing several messages, a response that holds an event's content back has the line quote the event to the agents its messages wake. An agent's upcoming wakes count each event in a batch that would wake it, one whose channel is held by delivery included.This addresses #243, for its module-event row's named agents. Its other rows stay as they are.
changelog.d/module-event-gate-recipients.fixed.mdandchangelog.d/upcoming-wake-agents.added.md.Credits
Paloma-2644 found it, and Ansel-2428 and Hilda-2681 triaged it. Milo-2653 built it and wrote this text. Ansel-2428, Nell-1783 and Gordon-2414 read the code, and Fiona-2757, Lottie-2661 and Jonah-2510 read this text. Ada-1017 decided its shape.
Details for agents
Head
463e4fd031de, thirty-five commits onmainat36b6dfe9de39, one of them a merge ofmain.Problem
At
36b6dfe9de39,applyProcessResponsestores a response's messages for the agents itsrequestInferencenames that read the slot they land in (requestedAudience,src/framework.ts:20294). Its call to the gate (:20247–:20253) names norecipients. It passes a lone message's placement, which marks the event as already in the window so the batch's line leaves it out, only for a write that names no agent (:20208). So when adebouncerule batches the event,deliverEventswakes every agentgetAgentNamesFnlists (src/gate/event-gate.ts:4213–4216). The framework sets that function to the registry'sgateRecipients()(src/framework.ts:5775).deliverBatchstores the batch's[Gate: …]line, quoting the event, as a write that names no agent (audienceundefined,src/gate/event-gate.ts:4215). Such a write is for every resident that takes untargeted inbound in that slot (untargetedAudience,src/framework.ts:34301). The direct path wakes only the named agents that the event's source can trigger (canBeTriggeredBy,src/framework.ts:20260–20276).In a batch mixing untargeted events, which have no list of recipients, with events that name theirs,
deliverEventsshows each agent it wakes every untargeted event (src/gate/event-gate.ts:4218–4229).upcomingWakescounts each pending batch for those agents and no others (:4404–4410), and adebouncebatch's wake iscertainfor all of them when it is for any one (:4417–4420). The judge is asked with every gate recipient's upcoming wakes (:4323), andifYouWaittells it all of them as what next wakes the one agentchooseAgentpicks (src/gate/reply-judge.ts:200–207,:345). A module response whose message is held from the residents (metadata.tuneOut) has the message stored for no one (defaultAudience,src/framework.ts:34276), but its event still joins the batch and is quoted in the line, and with no rule the direct path wakes a named resident to a turn whose request carries nothing it can see.The red runs under Tests show each case, with the tests on
9d57cc8138's source.Changes
src/framework.ts: the agents the direct path wakes, those named, registered and passingcanBeTriggeredBy(source), are worked out once, before the gate call. Of those, a request naming agents keeps the ones whose view shows a message the response stores (agentSees), where it stores any, reading each message's metadata asaddMessagestores it.metadataAsStoredholdsaddMessage's four steps on a write's metadata, moved unchanged into one function that both call. The gate call passesrecipients: those kept that are inrequestedAudience. An empty list passesrecipients: []. The direct path wakes the agents kept: as before, but for a resident a held message alone was for. The gate is given a lone message's placement whatever its audience, where the message isn't held from the residents, so a named event whose message is in its recipients' windows gets no line, as an untargeted one gets none. Admission reads adebounceor judge rule's verdict asmaindid: it never wakes at once, so the let-through of an MCPL event none of whose targets is registered wakes no one, and the hold's probe counts adebouncerule's batch as a pass and a judge rule's not.src/gate/types.ts:GateEventInfo.recipients' doc states whom an event is for, by kind: untargeted, named or an empty list, and how a batch, its line, upcoming wakes and a judge rule follow that.UpcomingWake.agents, new and optional, names the agents a wake would wake, of those its asker named,certain's doc says it's true or false of every agentagentsnames, andwhat's doc says that for a debounced batch it counts the events delivery gives the agents it names.GateEventInfo.recipients' doc says the framework sets it for a module's response to an event other than an MCPL push or channel message, and that admission, given a batching rule's pass, wakes no one for a targeted MCPL event none of whose targets is registered.src/gate/event-gate.ts:wokenBygives the agents a batch wakes: the recipients its events name, and the gate's recipients when any event is untargeted.evaluateleaves an event whose list of recipients is empty out of every batch, and adebounceor judge rule lets it through (trigger: true), inevaluateand in a probe.deliverEventsshows an untargeted event to the gate's recipients alone, and one that names its recipients to them.upcomingWakescounts a batch for an agent it would wake, and names on each wake, a self-wake's, a sleep's end and a batch's, the agents it would wake. Adebouncebatch is a wake for each group of agents with the same certainty and the same count of events delivery gives them.main: for the gate's recipients, with every event it holds.src/gate/reply-judge.ts:ifYouWaitkeeps the wakes that name the agent the judge reads, or name none, as the host's own wakes for that agent do.docs/dendrite.md: thereceivesGateWakesrow says a batched event that names its recipients wakes those, which of its named agents a module's response names, and that an event whose list of recipients is empty joins no batch.test/module-event-gate-recipients.test.ts: thirteen tests, andtest/gate-batch-recipients.test.ts, eight, below, with one intest/reply-judge.test.ts. The first file's module answers aclock:reminderwith one message, or a held one beside a visible one, asking inference for the agents the reminder names. Its helpers serve the file's tests alike:setupbuilds the host and counts turns,remindsends a reminder,firefires the held batch,rowsandaudienceOfread stored rows,gateAskedrecords what the gate is asked, andisolatedJobruns a job blocked in a tool. The gate file'smakeGateandfireserve its eight.test/debounce-seen-wake.test.tsandtest/event-gate-judge.test.ts,main's: three tests change wheremain's in-context gate events meet this change, below.test/mcpl-unregistered-targets.test.ts: six tests, below, of an MCPL event none of whose targets is registered here.Tests
Every run below was on GitHub's
ubuntu-26.04runner (image20261101.186.1, x64) with Node v22.12.0 and npm 10.9.0, afternpm install && npm run build. With no lockfile,npm installresolved these direct dependencies, asnpm lsprinted them:@animalabs/chronicle@0.6.0,@animalabs/context-manager@0.25.1,@animalabs/mcpl-core@0.4.0,@animalabs/membrane@0.9.0,@babel/parser@7.29.13,@modelcontextprotocol/client@2.4.0,@modelcontextprotocol/server@2.4.0,@types/node@22.20.5,@types/ws@8.18.2,chokidar@4.0.3,discord.js@14.28.1,tsx@4.23.15,typescript@7.0.2,ws@8.22.2. The catch-up's runs resolved@animalabs/context-manager@0.27.0and@animalabs/membrane@0.10.2, and the rest as listed.The first three commits.
217db1571647, the tests onmain's source: 4 of 4 fail. Tests 1 and 2 wake['agent', 'other']where['agent']is expected, test 3 wakes['agent', 'other']where[]is, and test 4 wakes['worker-1', 'agent']where['worker-1']is.429b19f4192c: 4 of 4 pass.node scripts/test-as-ci.mjsas CI runs it, at429b19f4192c: 10,600 pass, 0 fail, 62 skipped and 1 todo, of 10,663.The next three,
eb8e35782eto8350fdea6ffd.eb8e35782erewrites the module-event tests and adds the gate tests,46a59ee0d0changes the gate, and8350fdea6ffdchanges onlychangelog.d/anddocs/dendrite.md.Red, at
850fa581ed87:mainat9d57cc8138with the two test files as they are ateb8e35782e, on a branch of its own (nissa-seru:milo/2200-red-main-r1). 8 of 10 fail: module-event tests 1 to 4 and gate tests 1 to 4. Pins 5 and 6 pass.Red, at
eb8e35782e, the tests on this pull request's earlier code: the four gate tests fail, and the six module-event tests pass.Green, at
46a59ee0d0: 10 of 10 pass.test/module-event-gate-recipients.test.ts:agentalone, under adebouncerule, wakes onlyagent, and every row quoting it, the batch's line included, is stored with audience['agent'].triggerSources: ['editor']isn't woken by theclockreminder's batch.[]), batched beside one foragent: onlyagentis woken, and its line quotes its own reminder alone.deriveAgent,mode: 'copy', blocked in a tool while the reminders land), batched beside one foragent: the job's own turn andagent's, andagent's line quotes its own reminder alone.true) under the rule wakes both residents, with its line stamped for both.test/gate-batch-recipients.test.ts, against a gate whose own recipients areagentandother:sub:sub's line quotes its own event alone, and the residents' line the untargeted one.otherand one whose list of recipients is empty is judged for['other']and shown the first alone, and a batch of the second kind alone isn't judged.The whole suite, at
46a59ee0d0: 10,606 pass, 0 fail, 62 skipped and 1 todo, of 10,669.The last seven,
fc7ecfac34toe301f22523bb.fc7ecfac34and4bc913f97eadd tests, andfc7ecfac34rewrites the judge's and stops the module-event tests from counting a batch's events before firing it.6d3583836areverts the judge half of46a59ee0d0.734ab91cbachanges the gate and the module-event gate call, and001abbcceathe framework's choice of whom a named request wakes.0140e194a91achanges onlychangelog.d/anddocs/dendrite.md, ande301f22523bbonly the fragment and a doc comment. Below, the tests are numbered in001abbccea's file order: the module-event tests 1 to 4 as above, 5 to 8 the held cases, and the pins 9 and 10.45275192a9bf:mainat9d57cc8138with the two test files as they are at4bc913f97e(nissa-seru:milo/2200-red-main-r2). 12 of 15 fail. Module-event test 7 and the two pins pass.fc7ecfac34, and again at6d3583836a, with that commit's tests: 3 of 12 fail, the held message's, the judge's and the empty list's.4bc913f97e, the tests on734ab91cba's code: 2 of 15 fail, module-event tests 6 and 8.001abbccea: 15 of 15 pass. New or changed since46a59ee0d0:agentwhose message is held from the residents (tuneOut), batched beside one foragentthat isn't: onlyagentis woken, and its line quotes the second alone.agentwakes no one.agentsees wakesagent, and its request carries the one it sees.agentandSubconsciouswakes the subconscious alone, with no rule and under the rule, with the message in its request. The batch's line is stored for the subconscious alone.otherand one whose list of recipients is empty is judged for['agent', 'other']and shown the first alone.001abbccea: 10,611 pass, 0 fail, 62 skipped and 1 todo, of 10,674.dce8ae0d2a39changes only a doc comment insrc/gate/types.ts.The last three,
b8eff2c125to88f187ada9ef.b8eff2c125adds and changes tests,662d94e7f5changes the framework, the gate and the reply judge, and88f187ada9efchanges onlychangelog.d/anddocs/dendrite.md. Below, the tests are numbered in88f187ada9ef's file order.634a77c61ecc:mainat9d57cc8138with the three test files as they are atb8eff2c125(nissa-seru:milo/2200-red-main-r3). 15 of 36 fail: module-event tests 1 to 6, 8 and 10, the six gate tests, and the reply-judge test below.b8eff2c125, the tests ondce8ae0d2a39's code: 3 of 36 fail, gate test 4, module-event test 9 and the reply-judge test.662d94e7f5: 36 of 36 pass. New or changed:other, each wake upcoming for['agent', 'other']names['other'], and none isagent's. A batch of an untargeted event and a sleep that names no agent name both.Scout, the judge's list of what next wakes it leaves out a wake forotheralone, and keepsScout's and the host's own.suppressed) foragentis stored without it and wakesagent.agent, wakes no one, with no rule or under the rule.662d94e7f5: 10,615 pass, 0 fail, 62 skipped and 1 todo, of 10,678.The last three,
42b27fa3e4to3f3508949c85.42b27fa3e4changes tests,6a39888dd3changes the gate'sevaluateand its probe, the rule's doc and the framework (a comment), and3f3508949c85changes onlychangelog.d/anddocs/dendrite.md. Below, the tests are numbered in3f3508949c85's file order.4b9725cec6b4:mainat9d57cc8138with the three test files as they are at42b27fa3e4(nissa-seru:milo/2200-red-main-r4). 17 of 38 fail: module-event tests 1 to 7, 9 and 11, the seven gate tests, and the reply-judge test foragents.42b27fa3e4, the tests on88f187ada9ef's code: 4 of 38 fail, gate tests 5 and 6 and module-event tests 4 and 5.6a39888dd3: 38 of 38 pass. New or changed:trigger: true), alone and beside a pending batch, which it neither joins nor restarts.debouncerule and under a judge rule,probeandevaluateboth let such an event through, and a probe of a named event still batches.6a39888dd3: 10,617 pass, 0 fail, 62 skipped and 1 todo, of 10,680.c1af82661270changes only the fragment,1a04bdb5a8cdonly removes comments (green at it, 38 of 38 pass), andae6c5b3c6ed5changes only the fragment.The catch-up,
0e255e1a47toaeb59c3a3dfe.0e255e1a47mergesmainat36b6dfe9de39, which holds #972's in-context gate events.178e9d4b79changes three tests where the two meet,8e67953bb1andd80a56a6b2add and change tests,c1f7028306changes the framework's placement, and727b27e3d1the gate's upcoming wakes andUpcomingWake.certain's doc.c9f2557430changes only the fragment, andaeb59c3a3dfeonlyupcomingWakes' doc. Below, the tests are numbered inaeb59c3a3dfe's file order.18bab9c57142:mainat36b6dfe9de39with the five test files as they are atd80a56a6b2(nissa-seru:milo/2200-red-main-r5). 26 of 188 fail: module-event tests 1 to 7, 9 and 11, the eight gate tests, the reply-judge test foragents,debounce-seen-wake's test of a module message for the agent it asks inference for, and seven ofevent-gate-judge's: the six pending-batch cases, which readagents, and the split batch's case of one agent's event with no write.8e67953bb1, the tests on the merge's code: 1 of 187 fails, module-event test 1, whose resident's window holds the message and a line quoting it.d80a56a6b2, the tests onc1f7028306's code: 2 of 188 fail, gate test 5 andevent-gate-judge's case of one agent's event with no write.727b27e3d1: 188 of 188 pass. New or changed:agentunder the rule wakesagentalone, whose window holds the message once, with no line quoting it.agent's event, placed in its window, andother's, with no write. The judge foragentis told the batch may wake it, and the judge forotherthat it will.debounce-seen-wake's test of a module message stored for the agent it asks inference for: the batch wakes that agent, and not the resident outside its audience. Onmainit pinned that resident's wake.event-gate-judge's case of a pending batch that wakes a co-resident: its gate's recipients include the co-resident, through a newrecipientsoption on itsmakeGate. Its case of one agent's event with no write expects a wake for each agent. Its table of pending batches reads the wake for the last agent it asks about.727b27e3d1: 10,833 pass, 0 fail, 62 skipped and 1 todo, of 10,896.The last four,
4b898cab88to463e4fd031de.4b898cab88adds and changes tests,da7e7243ccchanges admission,424f3f53c0the gate's upcoming wakes andUpcomingWake.what's doc, and463e4fd031deonlychangelog.d/and the docs ofGateEventInfo.recipientsandUpcomingWake.what. The runs take eight files: the five above,test/mcpl-unregistered-targets.test.ts,test/conversation-routing.test.tsandtest/admission.test.ts. Below, the tests are numbered in463e4fd031de's file order.main's outcome, at8de5404c80f3:mainat36b6dfe9de39withtest/mcpl-unregistered-targets.test.tsalone (nissa-seru:milo/2200-main-mcpl-r6). Its tests 3, 5 and 6 pass. Tests 1, 2 and 4 stop at "it joins no batch", sincemainbatches such an event for no one; with that assert replaced by firing the batch, they pass onmaintoo, and the batch wakes no one.4b898cab88, the tests onaeb59c3a3dfe's code: 6 of 242 fail, gate tests 4 and 5 and the new file's tests 1, 2, 4 and 5.da7e7243cc, the tests on admission's fix alone: 2 of 242 fail, gate tests 4 and 5.424f3f53c0: 242 of 242 pass. New or changed:test/mcpl-unregistered-targets.test.ts, for an MCPL event none of whose targets is registered: under adebouncerule (1) and a judge rule (2), a DM routed to a conversation fork joins no batch and starts no turn, and (3) underalwaysit wakes the fork, as onmain. (4) Under adebouncerule a push queues no request. Held, the hold's probe gives no pass under a judge rule (5) and a pass under adebouncerule (6).otherand an untargeted one is a wake foragent, of one event, and one forother, of two. Gate test 5: each agent is told a batch of one event.event-gate-judge's table of pending batches gives each agent its own certainty and checks every agent's wake; its co-resident row only may wake the delivery agent.evaluate's placement and records each verdict, and tests 7 and 11 read that the gate let the event through to the direct path.424f3f53c0: 10,839 pass, 0 fail, 62 skipped and 1 todo, of 10,902.Not verified
debouncerule ran it. Every test uses the repository's mock provider.