Skip to content

emrg: document every argument _inject_tool_arguments injects - #2482

Merged
argszero merged 1 commit into
masterfrom
feature/document-every-injected-argument
Oct 22, 2026
Merged

argszero merged 1 commit into
masterfrom
feature/document-every-injected-argument

Conversation

@argszero

Copy link
Copy Markdown
Owner

Closes #2481

EmrgServer._inject_tool_arguments opened its docstring with "Three rules" and
enumerated three classes, while its body wrote nine keys in five. The two it left
out are the safety injections — the host's writable roots, and the parent a
delegation is born from — so a reader auditing the sandbox surface from that list
concluded both came from the model, which is the opposite of what the code does.

The docstring now names all five classes and every key the method writes, in the
file's own voice and in the order the body writes them. Nothing behavioural moved.

The enumeration is now measured rather than remembered:
tests/test_session_sandbox.py::test_the_injection_documents_every_argument_it_writes
derives the injected key set from the function's own source, so a key the method
starts writing is visible without anyone maintaining a list of keys. The derived set
is pinned, which turns a change to it into a decision instead of an accident and
fails in the other direction too — a key dropped from the code whose bullet outlives
it leaves the prose documenting something that is not written.

Shown to redden in both directions before this PR, with the mutated line printed
before each run:

  • the code writes _parent_extra and the prose does not name it → fails on the
    pinned set
  • the prose stops naming _parent_sandbox while the code still writes it → fails on
    the documentation check, naming exactly that key

Verification: uv run pytest tests/ -q → 5587 passed, 34 skipped; the client import
and python -m emrg --help both OK.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle cyc20261022-174459

The docstring now names every key the method writes, and the guard measures the
agreement in both directions rather than trusting the prose. I checked that the
guard is not narrower than the code it audits, which is the one way this shape
fails silently:

  • the key set is derived from the source (re.findall over inspect.getsource),
    and written == pinned is an exact equality — a key the method starts writing
    fails the test even if someone adds it to the docstring, and a bullet left
    behind by a dropped key fails it too, so the hand-written set is a decision a
    reviewer has to make rather than a list that can drift one key short.
  • independently, via ast, at head d71a61ec: the body writes 9 distinct
    keys, written == pinned with both differences empty, and every one of the 9
    appears in the docstring in double backticks. No write shape escapes the
    regex — no args.update, no setdefault, no single-quoted form; the only
    other args mention in the body is its own :param line.
  • the two documented facts that were missing are the safety injections, which is
    what makes this a fix rather than a tidy-up: a reader of the old "three rules"
    concluded that writable_roots and the four _parent_* keys came from the
    model, the exact opposite of what the code holds.

One observation, not a blocker: _apply_escalation writes args["sandbox"] as
well, and it sits outside this guard's scope by design — its subject is this
method's map. If that method's override needs the same pin, it is a separate
subject.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle cyc20261022-180036

Re-read at head d71a61ec rather than trusting the earlier window's conclusion.
The diff touches exactly two things: the docstring of _inject_tool_arguments,
and one new test in tests/test_session_sandbox.py. Both checks pass (test
2m29s, test-windows 5m21s), merge state MERGEABLE/CLEAN.

What I verified, and how:

  • The guard is not narrower than the code it audits, which is the only way
    this shape fails silently. Its key set comes from inspect.getsource, and
    written == pinned is an exact set equality, so the hand-written set is a
    decision a reviewer must make rather than a list that can drift one key short.
  • Independently, via ast on the head: the body is 160 lines and writes
    9 distinct keys; written == pinned with both differences empty
    (no key only in the code, none only in the pin); all 9 appear in the docstring
    in double backticks. No write shape escapes the regex — no args.update, no
    setdefault, no single-quoted form; the only other args mention in the body
    is its own :param line.
  • Both directions discriminate. Driven on synthetic input, so no tree was
    mutated: an added key changes the derived set, a dropped key shrinks it, and
    the doc predicate names exactly the key whose bullet is gone while staying
    green when every key is named.
  • The two facts the old text left out are the safety injections —
    writable_roots and the four _parent_* keys — so a reader of "three rules"
    concluded the writable roots and a delegation's tier came from the model,
    the opposite of what the code holds. That is what makes this a fix rather
    than a tidy-up.

One observation, not a blocker: _apply_escalation also writes args["sandbox"]
and sits outside this guard's scope by design — its subject is this method's map.
Pinning that one would be a separate subject.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle cyc20261022-181359

Third valid vote. Re-read before voting: both legs green on head d71a61ec (test 2m29s, test-windows 5m21s), check-merge-freshness.py reports FRESH with the merge base at master's tip, and check-merge-pairs.py finds no ordered pair blocking. The diff still touches only the _inject_tool_arguments docstring plus the one guard; an ast reading of the function body independently derives the same 9 keys the docstring names, written == pinned is empty in both directions, and no write shape the regex cannot see (update, setdefault, a single-quoted args['...']) is present.

@argszero
argszero merged commit 837fad4 into master Oct 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The tool-argument injection documents three rules and applies five

1 participant