Skip to content

emrg: the owner tool lets the caller choose the question, and is asked again before its judgement can have changed #2495

Closed

Description

@argszero

The owner tool lets the caller choose the question, and is asked again before its judgement can have changed

What is observed, and where

emrg/tools/boss_tool.py registers one tool, boss, with three parameters: intent, timeout_s, and focus. focus is documented as "the one thing you want the owner's judgement on", and emrg/server/prompts/boss.j2 renders it under the heading "The executor especially wants your judgement on this".

Two consequences follow, and they are separate defects.

1. The caller narrows what the owner judges. The owner role exists because the round that must finish something now is the worst judge of whether it should be doing it at all. A parameter that lets that same round choose the question hands part of that judgement back to it: an executor can ask the owner to rule on the thing the executor has already decided to do, and an answer to a narrowed question is not a direction.

2. Nothing notices that the direction was just decided. Every boss call opens the retained owner session and runs a full turn to completion (DEFAULT_TIMEOUT_S = 600). Measured in one scheduled task's own session history: five owner sessions began within 15.5 minutes, the shortest gap between two of them 30 seconds. A task's direction is not a quantity that changes on that timescale. Each of those calls paid for a complete agent run to re-derive an answer that was already given, and the executor had the previous answer in context.

What is expected instead

The owner decides what it judges. The tool keeps intent and timeout_s; focus is removed. The prompt already tells the owner to read the parent's history.jsonl and derive the mission itself, so it has everything it needs to choose.

A direction that was just given stands until the window closes. When an owner session for the same parent was asked within the last four hours, a boss call starts no agent and returns immediately, saying it is busy: it names when the previous request was made, when the window frees, and how long that is.

Situation Behaviour
Called with focus in the arguments Not accepted — the parameter no longer exists
Within four hours of the previous request No agent is started, no request is made; a busy result is returned
The busy result States that it is busy, when the previous request was made, when the window frees, how long remains, and that no direction was given this round
Outside the window Normal: a full owner session runs
Never called for this parent Normal: a full owner session runs
Daemon restarted The window still applies
error field The busy result is a normal result, not an error

What the fix must satisfy

A busy result must not be readable as a direction. Today's tool description tells the executor that what comes back "is a stance to treat as binding for this round, not a list of problems to consider". A busy answer delivered on that contract would be read as a stance — the round would take "nothing changes" from a call that said nothing at all. So the result carries a field a program can test (not a sentence a reader must interpret), and the executor's own instructions must gain the matching rule: on a busy answer, keep the direction you already have and carry on with this round. That sentence belongs in the same change as the removed parameter, because it is the other half of the same contract.

The window's clock is persisted, not remembered. The reference point is the instant of the previous request for that parent, and it must survive a daemon restart and a rebuild of the owner session. The precedent is already in this repository: a session's delegation depth lives in its meta.json "rather than in a daemon table because … a daemon restart must not reset the count of a session that already exists on disk" (emrg/session.py). The window needs the same property for the same reason; an in-memory timer, or a value recomputed from a file that _get_or_create_session may rewrite, does not have it.

focus is deleted, not ignored. The requirement is that passing it is not accepted. That means the parameter leaves the tool schema, its validation branch, the {% if focus %} block in boss.j2, the focus= keyword on _run_boss_tool and _run_boss_child, and the timeout error's advice to "narrow focus". Any caller left behind is a call that silently stops working, so the removal and its callers are one change.

Acceptance

  • A repository test asserts that focus is no longer an accepted parameter — passing it is refused rather than honoured.
  • A repository test asserts that a call inside the window starts zero owner sessions and that its result names the remaining time and states that no direction was given.
  • A test asserts that a call outside the window runs a full owner session, and that a parent that has never called runs one.
  • A test asserts the window survives a daemon restart: the decisive reading is taken after rebuilding the daemon object against the same on-disk state, not from a value the first object still holds.
  • A test asserts the busy result is not an error, and carries the field the executor's instructions key on.

On "three platforms": the Test workflow runs exactly two pytest legs, ubuntu-latest and windows-2025 (build-release.yml does not run the suite). A macOS leg does not exist, and adding one costs a runner slot on every PR for every change. This issue therefore claims the two legs that run, and states that the macOS case is not claimed — the window logic is platform-free, and what remains unmeasured is only the runner's own behaviour. Adding a macOS leg is a separate decision, not a quiet line in this issue's acceptance.

Activity

  1. argszero commented on Oct 22, 2026

    @argszero
    OwnerAuthor

    Handled by #2496

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