#!/usr/bin/env bash
-# Man_In_Grey — canonical entrypoint for Man_In_Grey
-# - Resolves repo root via this script’s location (…/release/shell/)
-# - Picks gasket at release/<arch>/man_in_grey_apply when present
-# - Falls back to Python inner executor
-# - Always invokes the Python orchestrator Man_In_Grey.py
-
+# man_in_grey — canonical entrypoint for Man_In_Grey
+# - Resolves repo → release dirs
+# - Requires the privileged gasket (single code path)
+# - Always invokes the Python orchestrator with --apply-cmd <gasket>
set -euo pipefail
-# --- resolve paths ---
-_this="${BASH_SOURCE[0]}"
+# --- resolve this script’s absolute path (portable) ---
+_this="${BASH_SOURCE[0]:-$0}"
+
if command -v realpath >/dev/null 2>&1; then
- _this_abs="$(realpath "$_this")"
+ _this_abs="$(realpath -- "$_this")"
else
- _this_abs="$(readlink -f "$_this" 2>/dev/null || (cd "$(dirname "$_this")" && pwd -P)/"$(basename "$_this"))"
+ if _tmp="$(readlink -f -- "$_this" 2>/dev/null)"; then
+ _this_abs="${_tmp}"
+ else
+ _dir="$(cd "$(dirname -- "$_this")" && pwd -P)"
+ _base="$(basename -- "$_this")"
+ _this_abs="${_dir}/${_base}"
+ fi
fi
-_shell_dir="$(cd "$(dirname "$_this_abs")" && pwd -P)" # .../release/shell
-_release_dir="$(cd "$_shell_dir/.." && pwd -P)" # .../release
-_repo_root="$(cd "$_release_dir/.." && pwd -P)" # repo root
-
-_py_release="$_release_dir/python3"
-_py_dev="$_repo_root/developer/source"
-
-_py_entry=""
-if [[ -f "$_py_release/Man_In_Grey.py" ]]; then
- _py_entry="$_py_release/Man_In_Grey.py"
-elif [[ -f "$_py_dev/Man_In_Grey.py" ]]; then
- _py_entry="$_py_dev/Man_In_Grey.py"
+_shell_dir="$(cd "$(dirname -- "$_this_abs")" && pwd -P)" # .../release/shell
+_release_dir="$(cd "${_shell_dir}/.." && pwd -P)" # .../release
+_repo_root="$(cd "${_release_dir}/.." && pwd -P)" # repo root
+
+# --- orchestrator path (prefer released copy) ---
+_py_release="${_release_dir}/python3/Man_In_Grey.py"
+_py_dev="${_repo_root}/developer/source/Man_In_Grey.py"
+if [[ -f "$_py_release" ]]; then
+ _py_entry="$_py_release"
+elif [[ -f "$_py_dev" ]]; then
+ _py_entry="$_py_dev"
else
echo "error: Man_In_Grey.py not found in release/python3/ or developer/source/" >&2
exit 2
fi
-# --- arch normalize ---
+# --- arch normalize (uname -m → release/<arch>) ---
_arch_raw="$(uname -m | tr '[:upper:]' '[:lower:]')"
case "$_arch_raw" in
- amd64|x64) _arch="x86_64" ;;
- x86_64) _arch="x86_64" ;;
- i386|i486|i586|i686) _arch="i686" ;;
- arm64|aarch64) _arch="aarch64" ;;
- armv7l) _arch="armv7l" ;;
- armv6l) _arch="armv6l" ;;
- riscv64) _arch="riscv64" ;;
- ppc64le|powerpc64le) _arch="ppc64le" ;;
- s390x) _arch="s390x" ;;
- *) _arch="$_arch_raw" ;;
+ amd64|x64) _arch="x86_64" ;;
+ x86_64) _arch="x86_64" ;;
+ i386|i486|i586|i686) _arch="i686" ;;
+ arm64|aarch64) _arch="aarch64";;
+ armv7l) _arch="armv7l" ;;
+ armv6l) _arch="armv6l" ;;
+ riscv64) _arch="riscv64";;
+ ppc64le|powerpc64le) _arch="ppc64le";;
+ s390x) _arch="s390x" ;;
+ *) _arch="$_arch_raw" ;;
esac
-_gasket="$_release_dir/$_arch/man_in_grey_apply"
-_apply_args=()
-if [[ -x "$_gasket" ]]; then
- _apply_args=(--apply-cmd "$_gasket")
+_gasket="${_release_dir}/${_arch}/man_in_grey_apply"
+if [[ ! -x "$_gasket" ]]; then
+ echo "error: gasket missing: ${_gasket}" >&2
+ echo "hint: from \$REPO_HOME/developer: run compile then release" >&2
+ exit 2
fi
-# --- run orchestrator ---
-exec python3 "$_py_entry" "${_apply_args[@]}" "$@"
+# --- run orchestrator (single code path via gasket) ---
+exec "${PYTHON:-python3}" "$_py_entry" --apply-cmd "$_gasket" "$@"
cand = repo_root/"release"/"python3"/"executor_inner.py"
return cand if cand.is_file() else None
-def _apply_via_gasket(cbor_bytes: bytes ,apply_cmd: Path ,args)-> int:
- cmd = [
- str(apply_cmd)
- ,"--plan" ,"-"
- ]
- if args.phase_2_print: cmd.append("--phase-2-print")
- if args.phase_2_then_stop: cmd.append("--phase-2-then-stop")
- if args.phase_2_wellformed_then_stop: cmd.append("--phase-2-wellformed-then-stop")
- if args.phase_2_sanity1_then_stop: cmd.append("--phase-2-sanity1-then-stop")
- if args.phase_2_validity_then_stop: cmd.append("--phase-2-validity-then-stop")
- if args.phase_2_sanity2_then_stop: cmd.append("--phase-2-sanity2-then-stop")
- proc = subprocess.run(cmd ,input=cbor_bytes)
- return proc.returncode
+def _apply_via_gasket(cbor_bytes: bytes, apply_cmd: Path, args) -> int:
+ cmd = [str(apply_cmd), "--plan", "-"] # <— tell gasket to read from stdin
+ if args.phase_2_print: cmd.append("--phase-2-print")
+ if args.phase_2_then_stop: cmd.append("--phase-2-then-stop")
+ if args.phase_2_wellformed_then_stop: cmd.append("--phase-2-wellformed-then-stop")
+ if args.phase_2_sanity1_then_stop: cmd.append("--phase-2-sanity1-then-stop")
+ if args.phase_2_validity_then_stop: cmd.append("--phase-2-validity-then-stop")
+ if args.phase_2_sanity2_then_stop: cmd.append("--phase-2-sanity2-then-stop")
+ proc = subprocess.run(cmd, input=cbor_bytes)
+ return proc.returncode
def _apply_via_inner_py(cbor_bytes: bytes ,inner_py: Path ,args)-> int:
cmd = [
os.close(fd) ; raise OSError("not a directory")
return fd
+
+
+
def check_sanity_2(journal: Journal)-> list[str]:
errs: list[str] = []
opened: dict[str ,int] = {}
except Exception as e:
errs.append(f"[{i}] cannot open destination dir: {d} ({e})")
- # also warn on multiple writes to same (d,f) without displacement/delete
- seen: set[tuple[str ,str]] = set()
- for i ,cmd in enumerate(journal.command_list ,start=1):
+ # detect multiple writes to same target without a reset (displace/delete)
+ last_action: dict[tuple[str, str], str] = {}
+ for i, cmd in enumerate(journal.command_list, start=1):
ad = cmd.arg_dict
- key = (ad.get("write_file_dpath_str") ,ad.get("write_file_fname"))
- if key in seen and cmd.name_str == "copy":
- errs.append(f"[{i}] multiple writes to same target without prior displace/delete: {_dst_from(ad)}")
- seen.add(key)
+ key = (ad.get("write_file_dpath_str"), ad.get("write_file_fname"))
+ op = cmd.name_str
+ if op == "copy":
+ if last_action.get(key) == "copy":
+ errs.append(f"[{i}] multiple writes to same target without prior displace/delete: {_dst_from(ad)}")
+ last_action[key] = "copy"
+ elif op in {"displace", "delete"}:
+ last_action[key] = op
finally:
for fd in opened.values():
# --- main stays a thin arg wrapper ------------------------------------------
-def main(argv: list[str]|None=None)-> int:
+# --- plan input helpers -------------------------------------------------------
+
+def _read_fd_all(fd: int) -> bytes:
+ "Read all bytes from an already-open file descriptor without closing it."
+ chunks: list[bytes] = []
+ while True:
+ try:
+ b = os.read(fd, 65536)
+ except InterruptedError:
+ continue
+ if not b:
+ break
+ chunks.append(b)
+ return b"".join(chunks)
+
+def _read_plan_bytes_from_args(args) -> bytes:
+ """
+ Input priority:
+ 1) --plan-fd <n> (gasket path; do not close fd)
+ 2) --plan - (stdin)
+ 3) --plan <file> (read from filesystem)
+ """
+ if getattr(args, "plan_fd", -1) is not None and args.plan_fd >= 0:
+ return _read_fd_all(args.plan_fd)
+ if args.plan in ("", "-"):
+ return sys.stdin.buffer.read()
+ return Path(args.plan).read_bytes()
+def main(argv: list[str] | None = None) -> int:
ap = argparse.ArgumentParser(
- prog="executor_inner.py"
- ,description="Man_In_Gray inner executor (decode → validate → apply)"
+ prog="executor_inner.py",
+ description="Man_In_Grey inner executor (decode → validate → apply)"
)
- ap.add_argument("--plan" ,required=True ,help="path to CBOR plan file")
- ap.add_argument("--phase-2-print" ,action="store_true" ,help="print decoded journal")
- ap.add_argument("--phase-2-then-stop" ,action="store_true" ,help="stop after print (no apply)")
- ap.add_argument("--phase-2-wellformed-then-stop" ,action="store_true" ,help="stop after wellformed checks")
- ap.add_argument("--phase-2-sanity1-then-stop" ,action="store_true" ,help="stop after sanity-1 checks")
- ap.add_argument("--phase-2-validity-then-stop" ,action="store_true" ,help="stop after validity checks")
- ap.add_argument("--phase-2-sanity2-then-stop" ,action="store_true" ,help="stop after sanity-2 checks")
- ap.add_argument("--plan" ,default="" ,help="path to CBOR plan file or '-' for stdin")
- ap.add_argument("--plan-fd" ,type=int ,default=-1 ,help=argparse.SUPPRESS)
+ # Single --plan plus a hidden --plan-fd used by the gasket
+ ap.add_argument(
+ "--plan",
+ default="-",
+ help="path to CBOR plan file or '-' for stdin"
+ )
+ ap.add_argument(
+ "--plan-fd",
+ type=int,
+ default=-1,
+ help=argparse.SUPPRESS
+ )
+
+ # phase-2 gates (same semantics as before)
+ ap.add_argument("--phase-2-print", action="store_true", help="print decoded journal")
+ ap.add_argument("--phase-2-then-stop", action="store_true", help="stop after print (no apply)")
+ ap.add_argument("--phase-2-wellformed-then-stop", action="store_true", help="stop after wellformed checks")
+ ap.add_argument("--phase-2-sanity1-then-stop", action="store_true", help="stop after sanity-1 checks")
+ ap.add_argument("--phase-2-validity-then-stop", action="store_true", help="stop after validity checks")
+ ap.add_argument("--phase-2-sanity2-then-stop", action="store_true", help="stop after sanity-2 checks")
args = ap.parse_args(argv)
- # load plan
+ # Read plan bytes from fd/stdin/file
try:
- if args.plan_fd >= 0:
- import os as _os
- data = _os.read(args.plan_fd ,1<<30)
- elif args.plan == "-":
- import sys as _sys
- data = _sys.stdin.buffer.read()
- elif args.plan:
- data = Path(args.plan).read_bytes()
- else:
- print("error: either --plan <file|-> or --plan-fd <n> is required" ,file=sys.stderr)
- return 2
+ data = _read_plan_bytes_from_args(args)
except Exception as e:
- print(f"error: failed to read plan: {e}" ,file=sys.stderr)
+ print(f"error: failed to read plan: {e}", file=sys.stderr)
return 2
+ # Decode CBOR → Journal
try:
journal = _journal_from_cbor_bytes(data)
except Exception as e:
- print(f"error: failed to decode CBOR: {e}" ,file=sys.stderr)
+ print(f"error: failed to decode CBOR: {e}", file=sys.stderr)
return 2
+ # Run the pipeline
return executor_inner(
- journal
- ,phase_2_print=args.phase_2_print
- ,phase_2_then_stop=args.phase_2_then_stop
- ,phase_2_wellformed_then_stop=args.phase_2_wellformed_then_stop
- ,phase_2_sanity1_then_stop=args.phase_2_sanity1_then_stop
- ,phase_2_validity_then_stop=args.phase_2_validity_then_stop
- ,phase_2_sanity2_then_stop=args.phase_2_sanity2_then_stop
+ journal,
+ phase_2_print=args.phase_2_print,
+ phase_2_then_stop=args.phase_2_then_stop,
+ phase_2_wellformed_then_stop=args.phase_2_wellformed_then_stop,
+ phase_2_sanity1_then_stop=args.phase_2_sanity1_then_stop,
+ phase_2_validity_then_stop=args.phase_2_validity_then_stop,
+ phase_2_sanity2_then_stop=args.phase_2_sanity2_then_stop,
)
if __name__ == "__main__":
--- /dev/null
+
+2025-09-20 16:21:44Z [Man_In_Grey:tester]
+
+port executor_outer.py to C integrate it with apply.c
+
+add more tests.
cand = repo_root/"release"/"python3"/"executor_inner.py"
return cand if cand.is_file() else None
-def _apply_via_gasket(cbor_bytes: bytes ,apply_cmd: Path ,args)-> int:
- cmd = [
- str(apply_cmd)
- ,"--plan" ,"-"
- ]
- if args.phase_2_print: cmd.append("--phase-2-print")
- if args.phase_2_then_stop: cmd.append("--phase-2-then-stop")
- if args.phase_2_wellformed_then_stop: cmd.append("--phase-2-wellformed-then-stop")
- if args.phase_2_sanity1_then_stop: cmd.append("--phase-2-sanity1-then-stop")
- if args.phase_2_validity_then_stop: cmd.append("--phase-2-validity-then-stop")
- if args.phase_2_sanity2_then_stop: cmd.append("--phase-2-sanity2-then-stop")
- proc = subprocess.run(cmd ,input=cbor_bytes)
- return proc.returncode
+def _apply_via_gasket(cbor_bytes: bytes, apply_cmd: Path, args) -> int:
+ cmd = [str(apply_cmd), "--plan", "-"] # <— tell gasket to read from stdin
+ if args.phase_2_print: cmd.append("--phase-2-print")
+ if args.phase_2_then_stop: cmd.append("--phase-2-then-stop")
+ if args.phase_2_wellformed_then_stop: cmd.append("--phase-2-wellformed-then-stop")
+ if args.phase_2_sanity1_then_stop: cmd.append("--phase-2-sanity1-then-stop")
+ if args.phase_2_validity_then_stop: cmd.append("--phase-2-validity-then-stop")
+ if args.phase_2_sanity2_then_stop: cmd.append("--phase-2-sanity2-then-stop")
+ proc = subprocess.run(cmd, input=cbor_bytes)
+ return proc.returncode
def _apply_via_inner_py(cbor_bytes: bytes ,inner_py: Path ,args)-> int:
cmd = [
os.close(fd) ; raise OSError("not a directory")
return fd
+
+
+
def check_sanity_2(journal: Journal)-> list[str]:
errs: list[str] = []
opened: dict[str ,int] = {}
except Exception as e:
errs.append(f"[{i}] cannot open destination dir: {d} ({e})")
- # also warn on multiple writes to same (d,f) without displacement/delete
- seen: set[tuple[str ,str]] = set()
- for i ,cmd in enumerate(journal.command_list ,start=1):
+ # detect multiple writes to same target without a reset (displace/delete)
+ last_action: dict[tuple[str, str], str] = {}
+ for i, cmd in enumerate(journal.command_list, start=1):
ad = cmd.arg_dict
- key = (ad.get("write_file_dpath_str") ,ad.get("write_file_fname"))
- if key in seen and cmd.name_str == "copy":
- errs.append(f"[{i}] multiple writes to same target without prior displace/delete: {_dst_from(ad)}")
- seen.add(key)
+ key = (ad.get("write_file_dpath_str"), ad.get("write_file_fname"))
+ op = cmd.name_str
+ if op == "copy":
+ if last_action.get(key) == "copy":
+ errs.append(f"[{i}] multiple writes to same target without prior displace/delete: {_dst_from(ad)}")
+ last_action[key] = "copy"
+ elif op in {"displace", "delete"}:
+ last_action[key] = op
finally:
for fd in opened.values():
# --- main stays a thin arg wrapper ------------------------------------------
-def main(argv: list[str]|None=None)-> int:
+# --- plan input helpers -------------------------------------------------------
+
+def _read_fd_all(fd: int) -> bytes:
+ "Read all bytes from an already-open file descriptor without closing it."
+ chunks: list[bytes] = []
+ while True:
+ try:
+ b = os.read(fd, 65536)
+ except InterruptedError:
+ continue
+ if not b:
+ break
+ chunks.append(b)
+ return b"".join(chunks)
+
+def _read_plan_bytes_from_args(args) -> bytes:
+ """
+ Input priority:
+ 1) --plan-fd <n> (gasket path; do not close fd)
+ 2) --plan - (stdin)
+ 3) --plan <file> (read from filesystem)
+ """
+ if getattr(args, "plan_fd", -1) is not None and args.plan_fd >= 0:
+ return _read_fd_all(args.plan_fd)
+ if args.plan in ("", "-"):
+ return sys.stdin.buffer.read()
+ return Path(args.plan).read_bytes()
+def main(argv: list[str] | None = None) -> int:
ap = argparse.ArgumentParser(
- prog="executor_inner.py"
- ,description="Man_In_Gray inner executor (decode → validate → apply)"
+ prog="executor_inner.py",
+ description="Man_In_Grey inner executor (decode → validate → apply)"
)
- ap.add_argument("--plan" ,required=True ,help="path to CBOR plan file")
- ap.add_argument("--phase-2-print" ,action="store_true" ,help="print decoded journal")
- ap.add_argument("--phase-2-then-stop" ,action="store_true" ,help="stop after print (no apply)")
- ap.add_argument("--phase-2-wellformed-then-stop" ,action="store_true" ,help="stop after wellformed checks")
- ap.add_argument("--phase-2-sanity1-then-stop" ,action="store_true" ,help="stop after sanity-1 checks")
- ap.add_argument("--phase-2-validity-then-stop" ,action="store_true" ,help="stop after validity checks")
- ap.add_argument("--phase-2-sanity2-then-stop" ,action="store_true" ,help="stop after sanity-2 checks")
- ap.add_argument("--plan" ,default="" ,help="path to CBOR plan file or '-' for stdin")
- ap.add_argument("--plan-fd" ,type=int ,default=-1 ,help=argparse.SUPPRESS)
+ # Single --plan plus a hidden --plan-fd used by the gasket
+ ap.add_argument(
+ "--plan",
+ default="-",
+ help="path to CBOR plan file or '-' for stdin"
+ )
+ ap.add_argument(
+ "--plan-fd",
+ type=int,
+ default=-1,
+ help=argparse.SUPPRESS
+ )
+
+ # phase-2 gates (same semantics as before)
+ ap.add_argument("--phase-2-print", action="store_true", help="print decoded journal")
+ ap.add_argument("--phase-2-then-stop", action="store_true", help="stop after print (no apply)")
+ ap.add_argument("--phase-2-wellformed-then-stop", action="store_true", help="stop after wellformed checks")
+ ap.add_argument("--phase-2-sanity1-then-stop", action="store_true", help="stop after sanity-1 checks")
+ ap.add_argument("--phase-2-validity-then-stop", action="store_true", help="stop after validity checks")
+ ap.add_argument("--phase-2-sanity2-then-stop", action="store_true", help="stop after sanity-2 checks")
args = ap.parse_args(argv)
- # load plan
+ # Read plan bytes from fd/stdin/file
try:
- if args.plan_fd >= 0:
- import os as _os
- data = _os.read(args.plan_fd ,1<<30)
- elif args.plan == "-":
- import sys as _sys
- data = _sys.stdin.buffer.read()
- elif args.plan:
- data = Path(args.plan).read_bytes()
- else:
- print("error: either --plan <file|-> or --plan-fd <n> is required" ,file=sys.stderr)
- return 2
+ data = _read_plan_bytes_from_args(args)
except Exception as e:
- print(f"error: failed to read plan: {e}" ,file=sys.stderr)
+ print(f"error: failed to read plan: {e}", file=sys.stderr)
return 2
+ # Decode CBOR → Journal
try:
journal = _journal_from_cbor_bytes(data)
except Exception as e:
- print(f"error: failed to decode CBOR: {e}" ,file=sys.stderr)
+ print(f"error: failed to decode CBOR: {e}", file=sys.stderr)
return 2
+ # Run the pipeline
return executor_inner(
- journal
- ,phase_2_print=args.phase_2_print
- ,phase_2_then_stop=args.phase_2_then_stop
- ,phase_2_wellformed_then_stop=args.phase_2_wellformed_then_stop
- ,phase_2_sanity1_then_stop=args.phase_2_sanity1_then_stop
- ,phase_2_validity_then_stop=args.phase_2_validity_then_stop
- ,phase_2_sanity2_then_stop=args.phase_2_sanity2_then_stop
+ journal,
+ phase_2_print=args.phase_2_print,
+ phase_2_then_stop=args.phase_2_then_stop,
+ phase_2_wellformed_then_stop=args.phase_2_wellformed_then_stop,
+ phase_2_sanity1_then_stop=args.phase_2_sanity1_then_stop,
+ phase_2_validity_then_stop=args.phase_2_validity_then_stop,
+ phase_2_sanity2_then_stop=args.phase_2_sanity2_then_stop,
)
if __name__ == "__main__":
#!/usr/bin/env bash
-# Man_In_Grey — canonical entrypoint for Man_In_Grey
-# - Resolves repo root via this script’s location (…/release/shell/)
-# - Picks gasket at release/<arch>/man_in_grey_apply when present
-# - Falls back to Python inner executor
-# - Always invokes the Python orchestrator Man_In_Grey.py
-
+# man_in_grey — canonical entrypoint for Man_In_Grey
+# - Resolves repo → release dirs
+# - Requires the privileged gasket (single code path)
+# - Always invokes the Python orchestrator with --apply-cmd <gasket>
set -euo pipefail
-# --- resolve paths ---
-_this="${BASH_SOURCE[0]}"
+# --- resolve this script’s absolute path (portable) ---
+_this="${BASH_SOURCE[0]:-$0}"
+
if command -v realpath >/dev/null 2>&1; then
- _this_abs="$(realpath "$_this")"
+ _this_abs="$(realpath -- "$_this")"
else
- _this_abs="$(readlink -f "$_this" 2>/dev/null || (cd "$(dirname "$_this")" && pwd -P)/"$(basename "$_this"))"
+ if _tmp="$(readlink -f -- "$_this" 2>/dev/null)"; then
+ _this_abs="${_tmp}"
+ else
+ _dir="$(cd "$(dirname -- "$_this")" && pwd -P)"
+ _base="$(basename -- "$_this")"
+ _this_abs="${_dir}/${_base}"
+ fi
fi
-_shell_dir="$(cd "$(dirname "$_this_abs")" && pwd -P)" # .../release/shell
-_release_dir="$(cd "$_shell_dir/.." && pwd -P)" # .../release
-_repo_root="$(cd "$_release_dir/.." && pwd -P)" # repo root
-
-_py_release="$_release_dir/python3"
-_py_dev="$_repo_root/developer/source"
-
-_py_entry=""
-if [[ -f "$_py_release/Man_In_Grey.py" ]]; then
- _py_entry="$_py_release/Man_In_Grey.py"
-elif [[ -f "$_py_dev/Man_In_Grey.py" ]]; then
- _py_entry="$_py_dev/Man_In_Grey.py"
+_shell_dir="$(cd "$(dirname -- "$_this_abs")" && pwd -P)" # .../release/shell
+_release_dir="$(cd "${_shell_dir}/.." && pwd -P)" # .../release
+_repo_root="$(cd "${_release_dir}/.." && pwd -P)" # repo root
+
+# --- orchestrator path (prefer released copy) ---
+_py_release="${_release_dir}/python3/Man_In_Grey.py"
+_py_dev="${_repo_root}/developer/source/Man_In_Grey.py"
+if [[ -f "$_py_release" ]]; then
+ _py_entry="$_py_release"
+elif [[ -f "$_py_dev" ]]; then
+ _py_entry="$_py_dev"
else
echo "error: Man_In_Grey.py not found in release/python3/ or developer/source/" >&2
exit 2
fi
-# --- arch normalize ---
+# --- arch normalize (uname -m → release/<arch>) ---
_arch_raw="$(uname -m | tr '[:upper:]' '[:lower:]')"
case "$_arch_raw" in
- amd64|x64) _arch="x86_64" ;;
- x86_64) _arch="x86_64" ;;
- i386|i486|i586|i686) _arch="i686" ;;
- arm64|aarch64) _arch="aarch64" ;;
- armv7l) _arch="armv7l" ;;
- armv6l) _arch="armv6l" ;;
- riscv64) _arch="riscv64" ;;
- ppc64le|powerpc64le) _arch="ppc64le" ;;
- s390x) _arch="s390x" ;;
- *) _arch="$_arch_raw" ;;
+ amd64|x64) _arch="x86_64" ;;
+ x86_64) _arch="x86_64" ;;
+ i386|i486|i586|i686) _arch="i686" ;;
+ arm64|aarch64) _arch="aarch64";;
+ armv7l) _arch="armv7l" ;;
+ armv6l) _arch="armv6l" ;;
+ riscv64) _arch="riscv64";;
+ ppc64le|powerpc64le) _arch="ppc64le";;
+ s390x) _arch="s390x" ;;
+ *) _arch="$_arch_raw" ;;
esac
-_gasket="$_release_dir/$_arch/man_in_grey_apply"
-_apply_args=()
-if [[ -x "$_gasket" ]]; then
- _apply_args=(--apply-cmd "$_gasket")
+_gasket="${_release_dir}/${_arch}/man_in_grey_apply"
+if [[ ! -x "$_gasket" ]]; then
+ echo "error: gasket missing: ${_gasket}" >&2
+ echo "hint: from \$REPO_HOME/developer: run compile then release" >&2
+ exit 2
fi
-# --- run orchestrator ---
-exec python3 "$_py_entry" "${_apply_args[@]}" "$@"
+# --- run orchestrator (single code path via gasket) ---
+exec "${PYTHON:-python3}" "$_py_entry" --apply-cmd "$_gasket" "$@"
--- /dev/null
+# Man_In_Grey acceptance filter (default template)
+# Return True to include a config file ,False to skip it.
+# You receive a PlanProvenance object named `prov`.
+#
+# Common fields:
+# prov.stage_root_dpath : Path
+# prov.config_abs_fpath : Path
+# prov.config_rel_fpath : Path
+# prov.read_dir_dpath : Path
+# prov.read_fname : str
+#
+# 1) Accept everything (default):
+# def accept(prov):
+# return True
+#
+# 2) Only a namespace:
+# def accept(prov):
+# return prov.config_rel_fpath.as_posix().startswith("dns/")
+#
+# 3) Exclude editor junk:
+# def accept(prov):
+# r = prov.config_rel_fpath.as_posix()
+# return not (r.endswith("~") or r.endswith(".swp"))
+#
+def accept(prov):
+ return True
--- /dev/null
+#!/usr/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
+
+set -euo pipefail
+set -x
+
+find "$1" -type f -exec cat_named {} \;
+
--- /dev/null
+#!/usr/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
+
+set -euo pipefail
+set -x
+
+find stage_test_0_out -type f -exec rm \-f {} \;
+
--- /dev/null
+#!/usr/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
+
+set -euo pipefail
+set -x
+
+find "$1" -type f -print
+
#!/usr/bin/env bash
-set -euo pipefail
-
-# discover repo root from here
script_afp=$(realpath "${BASH_SOURCE[0]}")
-TESTER_DIR="$(cd "$(dirname "$script_afp")/.." && pwd -P)"
-REPO_HOME="$(cd "$TESTER_DIR/.." && pwd -P)"
-
-ENTRY="$REL_SHELL/Man_In_Grey"
-GASKET="$REL_ARCH/man_in_grey_apply"
-
-# tester has a path to `release/shell`
-ENTRY="Man_In_Grey"
-
-# sanity
-[[ -x "$ENTRY" ]] || { echo "❌ missing entrypoint: $ENTRY (did you run developer/release?)" >&2; exit 2; }
-
-# ensure tester won’t hit privileged gasket refusal:
-ARCH_RAW=$(uname -m | tr '[:upper:]' '[:lower:]')
-case "$ARCH_RAW" in
- amd64|x64) ARCH="x86_64" ;;
- x86_64) ARCH="x86_64" ;;
- i386|i486|i586|i686) ARCH="i686" ;;
- arm64|aarch64) ARCH="aarch64" ;;
- armv7l) ARCH="armv7l" ;;
- armv6l) ARCH="armv6l" ;;
- riscv64) ARCH="riscv64" ;;
- ppc64le|powerpc64le) ARCH="ppc64le" ;;
- s390x) ARCH="s390x" ;;
- *) ARCH="$ARCH_RAW" ;;
-esac
-GASKET="$REPO_HOME/release/$ARCH/man_in_grey_apply"
-
-if [[ -x "$GASKET" && -u "$GASKET" ]]; then
- echo "⚠️ Gasket is blessed (setuid-root) but tester is sudo-less."
- echo " Run: sudo ./tool/unbless"
- exit 1
-fi
-
-# fresh output dir
-rm -rf -- "$OUT"
-mkdir -p "$OUT"
-echo "▶️ Running Man_In_Grey on tester/$STAGE → $OUT"
-# Run planner → CBOR → apply (unprivileged). Default filter will be emitted in CWD if missing.
-( cd "$TESTER_DIR" && \
- "$ENTRY" \
- --stage "$STAGE" \
- --phase-1-print \
- --phase-2-print )
-
-echo "✅ Apply finished. Verifying…"
-
-fail=0
-
-# expected artifacts (from your sample stage)
-chk() {
- local path="$1" desc="$2"
- if [[ -f "$path" ]]; then
- echo " ✓ $desc ($path)"
- else
- echo " ✗ $desc missing ($path)"; fail=1
- fi
-}
-
-# files to expect
-chk "$OUT/unbound_conf" "DNS base file"
-chk "$OUT/net/unbound.conf" "DNS net override"
-chk "$OUT/web/nginx.conf" "web nginx.conf"
-
-# content spot checks (adjust to your test content)
-if [[ -f "$OUT/net/unbound.conf" ]]; then
- grep -q 'verbosity: 1' "$OUT/net/unbound.conf" \
- && echo " ✓ verbosity content OK" \
- || { echo " ✗ expected 'verbosity: 1' in net/unbound.conf"; fail=1; }
-fi
-
-if [[ -f "$OUT/web/nginx.conf" ]]; then
- grep -q 'listen 8080' "$OUT/web/nginx.conf" \
- && echo " ✓ nginx listen OK" \
- || { echo " ✗ expected 'listen 8080' in web/nginx.conf"; fail=1; }
-fi
-
-# mode spot check (0444 example; chmod prints in octal differently across distros, use stat)
-if [[ -f "$OUT/unbound_conf" ]]; then
- mode=$(stat -c '%a' "$OUT/unbound_conf" 2>/dev/null || stat -f '%Lp' "$OUT/unbound_conf")
- [[ "$mode" == "444" ]] \
- && echo " ✓ mode unbound_conf is 0444" \
- || { echo " ⚠︎ mode unbound_conf is $mode (expected 444)"; :; }
-fi
+set -euo pipefail
+set -x
-[[ $fail -eq 0 ]] && echo "🎉 test_0 PASS" || { echo "❌ test_0 FAIL"; exit 1; }
+$RELEASE_SHELL/Man_In_Grey --stage stage_test_0
--- /dev/null
+#!/usr/bin/env bash
+script_afp=$(realpath "${BASH_SOURCE[0]}")
+
+set -euo pipefail
+set -x
+
+./clean_out
+
+echo "first run"
+./run
+diff -qr stage_test_0_out stage_test_0_out_expected_0
+
+echo "second run"
+./run
+diff -qr stage_test_0_out stage_test_0_out_expected_1
--- /dev/null
+# due to file dates, the second check will find differences in file date pairs
+#
+# pass 1
+# Yes—this is a clean PASS ✅
+# started clean,
+# ran Man_In_Grey once → all three outputs appeared with expected content,
+# snapshotted as stage_test_0_out_expected_0.
+#
+# pass 2
+# Yes—this is a clean PASS ✅
+# web/nginx.conf and unbound_conf were displaced on the 2nd run → timestamped backups created, new files written.
+#
+# net/unbound.conf shows no backup, which is correct because that config does delete then copy (so overwrite without keeping a prior version). If you want a backup there too, switch that entry from delete→displace.
+
+
+2025-09-20 16:12:28Z [Man_In_Grey:tester] Thomas-developer@StanleyPark
+§/home/Thomas/subu_data/developer/project/active/Man_In_Grey/tester/test_0§
+> ./run_check
++ ./clean_out
++ find stage_test_0_out -type f -exec rm -f '{}' ';'
++ echo 'first run'
+first run
++ ./run
++ /home/Thomas/subu_data/developer/project/Linux/Man_In_Grey/release/shell/Man_In_Grey --stage stage_test_0
++ diff -qr stage_test_0_out stage_test_0_out_expected_0
++ echo 'second run'
+second run
++ ./run
++ /home/Thomas/subu_data/developer/project/Linux/Man_In_Grey/release/shell/Man_In_Grey --stage stage_test_0
++ diff -qr stage_test_0_out stage_test_0_out_expected_1
+Only in stage_test_0_out_expected_1: unbound_conf.20250920T160648Z
+Only in stage_test_0_out: unbound_conf.20250920T161232Z
+Only in stage_test_0_out_expected_1/web: nginx.conf.20250920T160648Z
+Only in stage_test_0_out/web: nginx.conf.20250920T161233Z
+
+2025-09-20 16:12:33Z [Man_In_Grey:tester] Thomas-developer@StanleyPark
+§/home/Thomas/subu_data/developer/project/active/Man_In_Grey/tester/test_0§
+>
--- /dev/null
+server:
+ verbosity: 1
--- /dev/null
+server:
+ do-ip6: no
--- /dev/null
+server:
+ do-ip6: no
--- /dev/null
+events {}
+http { server { listen 8080; } }
--- /dev/null
+events {}
+http { server { listen 8080; } }
--- /dev/null
+server:
+ verbosity: 1
--- /dev/null
+server:
+ do-ip6: no
--- /dev/null
+events {}
+http { server { listen 8080; } }
--- /dev/null
+server:
+ verbosity: 1
--- /dev/null
+server:
+ do-ip6: no
--- /dev/null
+server:
+ do-ip6: no
--- /dev/null
+events {}
+http { server { listen 8080; } }
--- /dev/null
+events {}
+http { server { listen 8080; } }
esac
export ARCH="$_arch"
-# Handy convenience paths (optional)
-export REL_SHELL="$RELEASE/shell"
-export REL_PY="$RELEASE/python3"
-export REL_ARCH="$RELEASE/$ARCH"
+# important release directories the main program call is in RELEASE_SHELL
+export RELEASE_SHELL="$RELEASE/shell"
+export RELEASE_PY="$RELEASE/python3"
+export RELEASE_ARCH="$RELEASE/$ARCH"
The binary should exist and report a working Python interpreter when run.
+6. Install cbor2
+
+ which python3
+ python3 -m pip install --upgrade pip
+ python3 -m pip install cbor2
+
+
* Notes
- The virtual environment is deliberately named =Python=, not =venv=, to reflect its role as a shared system component.