Files
multi-agent-mux/.agents/skills/lib_py/ints.py
T
GodopuandClaude Opus 5.5 63d9c205ff refactor(issue-17): item 4 - the delegate-job wrapper's decisions move to Python
The wrapper keeps spawn / wait / kill, key injection and the herdr
diagnostic probe; what it decided in bash is now lib_py/delegation/wrapper.py,
reached through one `_decide` helper:

- finalize_unfinished: the clock choice, the disk grace and broker
  re-observation, the close request / label, the close and the event
  (finalize-begin / finalize-end; bash runs only the busy probe between them)
- start_stall_watch: whether to watch (MAM_STALL_WATCH, remote, human)
- _map_sub_rc, _rc_for (+ MAM_DELEGATE_FAIL_CLOSED), the subscriber
  early-exit check and cmd_wait's rc normalisation
- mam_int / mam_int_knob run lib_py/ints.py, which is also the runner's
  _positive_int: one implementation of the Issue #26 rule

No behaviour change: tests/test_issue17_item4_decisions.py runs the old
bash functions (copied verbatim from 7209750) and the new wrapper on the
same inputs and compares output, FINAL_JOB_STATUS and the registry /
publish calls. Three static tests that pinned the old bash literals now
pin the Python entry points instead.

Refs #17

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 04:59:58 +00:00

64 lines
2.2 KiB
Python

"""Issue #26 / #17 item 4: the one integer rule for knobs and flags.
lib_int.sh's mam_int / mam_int_knob run this file, and the loop runner's
_positive_int is positive_int below, so bash and Python share one
implementation. Surrounding ASCII blanks are allowed, then ASCII digits only,
read as DECIMAL (bash would read 0700 as octal 448), and
minimum <= n <= 999999999. The per-knob minimum lives in
tests/test_issue26_ints.py.
Stdlib only and Python 3.9: lib_int.sh runs it as a script (python3 -I),
where lib_py is not importable.
ints.py int <value> <min> print n, or exit 1
ints.py knob <name> <value> <default> <min> print n; empty gives <default>,
invalid gives <default> + a warning
"""
from __future__ import annotations
import sys
from typing import List, Optional
_BLANKS = " \t\n\r\v\f"
def positive_int(text: Optional[str], minimum: int = 1) -> Optional[int]:
"""n when `text` is a decimal integer >= minimum (and <= 999999999), else None."""
s = (text or "").strip(_BLANKS)
if not s or not s.isascii() or not s.isdigit():
return None
s = s.lstrip("0") or "0"
if len(s) > 9: # bounded before int(), which refuses > 4300 digits
return None
n = int(s)
return n if n >= minimum else None
def knob(name: str, raw: str, default: str, minimum: int) -> str:
"""mam_int_knob: the value of $name by the rule, <default> when empty or invalid."""
if not raw:
return default
n = positive_int(raw, minimum)
if n is not None:
return str(n)
print(f"WARNING: {name}={raw} ignored (not a decimal integer >= {minimum}); using {default}", file=sys.stderr)
return default
def main(argv: List[str]) -> int:
if len(argv) == 3 and argv[0] == "int":
n = positive_int(argv[1], int(argv[2]))
if n is None:
return 1
print(n)
return 0
if len(argv) == 5 and argv[0] == "knob":
print(knob(argv[1], argv[2], argv[3], int(argv[4])))
return 0
print("usage: ints.py int <value> <min> | knob <name> <value> <default> <min>", file=sys.stderr)
return 2
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))