Initial Commit
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
"""`finish` must accept what the model actually sends, not only the schema.
|
||||
|
||||
python3 tests/test_vm_finish_shapes.py
|
||||
|
||||
WHY
|
||||
|
||||
A session wrote the script, syntax-checked it, built a fourteen-file test
|
||||
tree with awkward filenames, cross-checked its output against an
|
||||
independent listing, demonstrated the error paths, committed, and passed
|
||||
its own verification command. Then it could not close.
|
||||
|
||||
`finish` declares `verification` as an object - `{command, expected}` -
|
||||
and the model sends the command as a bare string often enough to matter.
|
||||
`v_finish` called `.get` on it, which raised
|
||||
|
||||
AttributeError: 'str' object has no attribute 'get'
|
||||
|
||||
out of the verb. The agent saw only "the supervisor refuses the call",
|
||||
tried seven times with varying arguments, then marked the task blocked
|
||||
and gave up. All the work was done and committed; the session simply
|
||||
could not be ended.
|
||||
|
||||
The identical mistake had already been found and fixed in the live view's
|
||||
renderer. That one cost a line of output. This one cost the end of a
|
||||
session - so the rule is the same wherever a model-supplied value is
|
||||
read: take what arrives, not what was asked for.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
VMD = os.path.join(HERE, "..", "vm", "vmd")
|
||||
|
||||
FAILS: list[str] = []
|
||||
|
||||
|
||||
def check(label: str, condition: bool, detail: str = "") -> None:
|
||||
if condition:
|
||||
print(f"ok {label}")
|
||||
else:
|
||||
FAILS.append(label)
|
||||
print(f"FAIL {label}\n {detail}")
|
||||
|
||||
|
||||
SRC = open(os.path.join(VMD, "vmd.py"), encoding="utf-8").read()
|
||||
body = SRC[SRC.index("def v_finish"):SRC.index("def v_report")]
|
||||
|
||||
|
||||
def normalise(value):
|
||||
"""The shape-tolerant read, lifted out of v_finish so it can be tested."""
|
||||
check_ = value
|
||||
if isinstance(check_, str):
|
||||
check_ = {"command": check_}
|
||||
elif not isinstance(check_, dict):
|
||||
check_ = {}
|
||||
return str(check_.get("command", "")).strip(), str(check_.get("expected", "")).strip()
|
||||
|
||||
|
||||
# --- what the model sends -------------------------------------------------
|
||||
check("the documented shape works",
|
||||
normalise({"command": "pytest -q", "expected": "0 failed"})
|
||||
== ("pytest -q", "0 failed"))
|
||||
check("a bare string is taken as the command",
|
||||
normalise("bash -n topfiles.sh") == ("bash -n topfiles.sh", ""),
|
||||
"this is the one that raised AttributeError and ended the session")
|
||||
check("a missing verification is empty, not an exception",
|
||||
normalise(None) == ("", ""))
|
||||
for junk in (12, [], ["a"], True):
|
||||
got = normalise(junk)
|
||||
check(f"{type(junk).__name__} does not raise", got == ("", ""), str(got))
|
||||
|
||||
# --- and the real verb does the same --------------------------------------
|
||||
check("v_finish normalises before reading",
|
||||
"isinstance(check, str)" in body and 'check = {"command": check}' in body,
|
||||
"the verb itself has to do this, not just this test")
|
||||
check("it no longer calls .get on whatever arrived",
|
||||
'(args.get("verification") or {}).get(' not in body,
|
||||
"that is the exact expression that raised")
|
||||
check("a verification with no command is still refused clearly",
|
||||
"finish needs a verification" in body,
|
||||
"tolerating the shape must not mean accepting nothing")
|
||||
|
||||
print()
|
||||
if FAILS:
|
||||
print(f"FAILED {len(FAILS)}")
|
||||
raise SystemExit(1)
|
||||
print("finish takes what the model sends, and a finished session can end")
|
||||
Reference in New Issue
Block a user