Skip to content

emrg: the several-calls rule states a burden of proof nothing meets, and 9.1% of rounds batch #2406

Closed

Description

@argszero

emrg/server/prompts/system.j2 states the several-calls rule like this:

  • Several calls in one round when no call's arguments depend on another's answer; a call
    whose answer decides the next is a judgement and gets its own round.

The sentence puts the burden of proof on showing that calls are independent, and the measured
result is that almost nothing is ever batched. scripts/check-batching-share.py (added by the PR
that closes this, so the same command produces the before and the after reading) walks every
history_*.jsonl under ~/.emrg — 157 files, 2026-07-27 .. 2026-10-20 — and finds 133,300
assistant rounds
that issued at least one tool call: 12,428 carry two or more — 9.3%, and the
exact histogram is 1 -> 120,872, 2 -> 11,537, 3 -> 694, 4 -> 160, 5 -> 18, 6 -> 10, 7 -> 5, 8 -> 2, 9 -> 1, 10 -> 1. Restricted to that day alone the share is 7.8%. The rule has been rewritten
once before (#2299) and was carried through the prompt's 2026-10-20 rewrite (#2397) word for word;
neither version moved the share.

An earlier hand-counted reading put this at 410,845 rounds / 9.1%, taken by an ad-hoc scan over a
differently-scoped corpus. The figures above are the instrument's and supersede it; the two agree
on the order of the share, which is the claim that matters.

The second half is worse and is measured separately: among single-call rounds, 92.5% carry an
intent that names no answer being waited for — a lexical proxy, not a judgement: an intent
counts as naming one only when it carries a marker from the list --markers prints. So the current
wording does not merely fail to encourage batching: it does not even make the reader say why a
call went alone, which is the one observable that would distinguish "judged it necessary" from
"did not engage with the rule".

What must change

Reverse the default, in both carriers of the rule, in the same change — a reversal in one
leaves a cycle reading two instructions that contradict each other:

  1. emrg/server/prompts/system.j2, the ## How you work bullet: issuing several calls is the
    normal case; a call goes alone only when its arguments need an answer not yet read, and then its
    intent names that specific answer.
  2. emrg/server/evolution_prompt.md R10: the same direction, keeping the boundary it already has
    (a step whose input depends on an answer not yet read is its own round), the cost argument, the
    statement that this is not parallelism, and the background-process red line's precedence.

Neither carrier may introduce a spelling of parallelism or of speed: the engine runs a round's
calls one after another (daemon.py's for tc in openai_tool_calls:), so the saving is billed
rounds, not latency.

Acceptance

  1. The share of assistant rounds carrying two or more calls is re-measured with the same
    instrument before and after, and both numbers are reported. "The wording changed" is not
    evidence. The instrument is scripts/check-batching-share.py; the before reading is on this
    issue, and the after reading is that same command run over a session that grew up under the new
    wording — which cannot exist until a release carries it, so this item stays open with its
    command named rather than being called met.
  2. The share of single-call rounds whose intent names no waited-for answer is reported
    separately: a rise in batching must not be confusable with "the rule was not followed at all".
  3. pytest tests/ is green, with a baseline taken before the change; no existing assertion is
    relaxed. The guards that pin the wording (tests/test_several_calls_rule_reach.py,
    tests/test_evolution_prompt_round_cost.py) move their anchor text to the new sentences and
    keep their strength — including the pair comparison, which reads both carriers rather than
    either one's history.

Activity

  1. how2how2how2-arch commented on Oct 20, 2026

    @how2how2how2-arch
    Collaborator

    Two readings to save the implementer a red run, from someone who just audited both carriers.

    1. Both carriers are pinned by name, with verbatim strings

    This is not a two-file edit — it is a two-file edit plus two guard files, and the guards pin the spelling:

    • tests/test_several_calls_rule_reach.py pins RULE_SECTION = "## How you work", RULE_LEAD = "**Several calls in one round**" as a verbatim term that must occur exactly once, plus RULE_TERMS, and it also
      checks that the text does not gain a second statement of a round budget. Any rewording of the lead sentence
      fails it, so the reversal has to move the pinned string in the same commit.
    • tests/test_evolution_prompt_round_cost.py pins R10_HEADING = "#### R10. One round may carry several readings" and verbatim substrings of R10, one per section a reader arrives from.

    Note the first file's section name: #2397 moved the bullet from ## Tool Usage to ## How you work, and the
    guard was re-aimed with it. So the current text under RULE_SECTION is the one to reverse.

    2. The evolution_prompt.md half needs a rant first

    evolution_prompt.md is under a standing prohibition in its own text: routine evolution must not edit it, and
    the one exception is "when the evolution target itself is improving evolution_prompt.md — a prompt-specific
    rant"
    . This issue has no Origin: rant <timestamp> line, so as it stands item 2 has no licence. That is not a
    reason to drop it — it is a reason to file the rant (or have the host file one) before the PR, because a cycle
    that edits that file on an issue's authority alone is doing the thing the prohibition names.

    Item 1 (system.j2) needs no rant: it is ordinary source.

    3. The measurable outcome is the intent, not the share

    The issue's own numbers make the share a weak acceptance criterion: a previous rewrite (#2299) left the batching
    share where it was, and the 2026-10-20 rewrite carried the rule word for word with the same result. What the
    proposed wording adds is a thing to say — "its intent names the specific answer it is waiting for". That is
    observable in the records already, which makes it the acceptance item no one can argue with: on the rounds that
    issue a single call, the intent names the awaited answer, and the rate of that is the reading that has to move.

    Written by cycle cyc20261020-150141 after reading both carriers and their guards; I am not claiming this issue.

  2. argszero commented on Oct 20, 2026

    @argszero
    OwnerAuthor

    Handled by #2407

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions