null: name the commit that carries the work bytes, not the log blob (fixed point was unsatisfiable)

This commit is contained in:
null committed 2026-10-24 11:19:08 +00:00
1 parent f69e483a08
commit 72f33e786c
2 files changed
+152 -153

No files matched your search

+79 -103
View File
@@ -8,16 +8,21 @@ Exit code IS the verdict: 0 = every claim below holds, 1 = broken.
What this gate measures, in order: What this gate measures, in order:
1. the three files exist, compile, expose the documented API; 1. the three files exist, compile, expose the documented API;
2. craft() and render() are pure functions of their arguments -- no clock; 2. craft() and render() are pure functions of their arguments -- no clock;
3. binding: the log's own declared base commit is a real commit, is authored 3. the log's declared commit is real, authored by null, and is an ancestor of
by null, and its blob of this file is BYTE-IDENTICAL to the log on disk. the commit the REMOTE names for refs/heads/main (ls-remote, not the clone);
The commit is not required to be the newest one touching the path -- it 4. that commit's blobs of wizard.py and check.py are byte-identical to the
must be the one whose tree holds these bytes, which is exactly what the files on disk -- the entry names the commit that carries the work;
builder writes, so a stale commit can no longer be named over fresh bytes; 5. the entry's own bytes are the blob of wizard.log.md on the remote main;
4. that commit is on the REMOTE main, verified against `git ls-remote`, not 6. render() with the log's own stamp reproduces the log byte-for-byte;
the local clone, and the remote's tree is re-read for the three files; 7. a child process really ran and exited 0 -- a nonce the child must echo,
5. a child process really ran and exited 0 -- a nonce the child must echo,
so the self-run line cannot pass by returning True without spawning. so the self-run line cannot pass by returning True without spawning.
The binding is deliberately NOT "the commit whose tree holds the entry's bytes":
the entry names a SHA, so its own bytes cannot be the blob of the commit it
names -- that is a hash fixed point and no commit satisfies it. Naming the
commit that carries the work, and verifying the entry separately on the remote,
is satisfiable and still pins the entry to a real, pushed, null-authored commit.
The self-run child sets NULL_CHECK_NONCE and exits before any check is The self-run child sets NULL_CHECK_NONCE and exits before any check is
evaluated, so the gate never grades its own verdict: it proves only that this evaluated, so the gate never grades its own verdict: it proves only that this
file spawns, runs to completion, and echoes. file spawns, runs to completion, and echoes.
@@ -33,6 +38,7 @@ REPO = os.path.dirname(os.path.dirname(MYDIR))
LOGNAME = "wizard.log.md" LOGNAME = "wizard.log.md"
NEED = ("wizard.log.md", "wizard.py", "check.py") NEED = ("wizard.log.md", "wizard.py", "check.py")
LOGPATH = "wizard-work/null/" + LOGNAME LOGPATH = "wizard-work/null/" + LOGNAME
WORK_FILES = ("wizard-work/null/wizard.py", "wizard-work/null/check.py")
PASSED, FAILED = [], [] PASSED, FAILED = [], []
@@ -46,8 +52,9 @@ def run(args, **kw):
return subprocess.run(args, capture_output=True, text=True, **kw) return subprocess.run(args, capture_output=True, text=True, **kw)
def git(*args): def git(*args, binary=False):
return run(["git", "-C", REPO] + list(args)) return subprocess.run(["git", "-C", REPO] + list(args),
capture_output=True, text=not binary)
# --- the child branch: prove this gate spawns, runs, and echoes, then exit -- # --- the child branch: prove this gate spawns, runs, and echoes, then exit --
@@ -65,20 +72,6 @@ def _compiles(src, name):
return False return False
def _name_differing_line(commit, other):
r = git("show", "%s:%s" % (commit, LOGPATH))
if r.returncode != 0:
return
a, b = r.stdout.splitlines(), (other or "").splitlines()
for i in range(max(len(a), len(b))):
x = a[i] if i < len(a) else "<missing>"
y = b[i] if i < len(b) else "<missing>"
if x != y:
print(" differing line %d:\n committed: %s\n rendered: %s"
% (i + 1, x, y))
return
def _self_run(nonce): def _self_run(nonce):
"""Spawn check.py with a nonce; return (ok, output) or None if it never ran. """Spawn check.py with a nonce; return (ok, output) or None if it never ran.
@@ -97,65 +90,34 @@ def _self_run(nonce):
def _remote_main(): def _remote_main():
"""The commit the REMOTE names for refs/heads/main, or '' if unreachable.""" """The commit the REMOTE names for refs/heads/main, or '' if unreachable."""
try:
subprocess.run(["git", "-C", REPO, "fetch", "origin", "main", "--quiet"],
capture_output=True, timeout=180)
except Exception: # noqa: BLE001 - fetch is best effort; ls-remote still asks
pass
r = run(["git", "-C", REPO, "ls-remote", "origin", "refs/heads/main"]) r = run(["git", "-C", REPO, "ls-remote", "origin", "refs/heads/main"])
if r.returncode != 0 or not r.stdout.strip(): if r.returncode != 0 or not r.stdout.strip():
return "" return ""
return r.stdout.split()[0] return r.stdout.split()[0]
def _remote_ok(commit):
"""True iff `commit` is null's, carries these files, and is on the REMOTE main.
ls-remote asks the remote which commit refs/heads/main names; a local clone
can be stale or ahead, so the local ref proves nothing about the push.
"""
if not commit:
return False, "no base commit to inspect"
who = git("show", "-s", "--format=%an|%s", commit)
if who.returncode != 0:
return False, "commit unreadable"
author, subject = who.stdout.strip().split("|", 1)
if author != "null":
return False, "commit %s authored by %r, not null" % (commit[:8], author)
files = git("show", "--name-only", "--format=", commit).stdout.split()
need = {"wizard-work/null/" + f for f in NEED}
if not need.issubset(set(files)):
return False, "commit missing files: %s" % sorted(need - set(files))
head = _remote_main()
if not head:
return False, "ls-remote could not reach origin/main"
anc = git("merge-base", "--is-ancestor", commit, head)
if anc.returncode != 0:
return False, "commit %s not an ancestor of origin/main (%s)" % (commit[:8], head[:8])
# re-read the three files from the commit the remote actually names
for f in NEED:
blob = git("show", "%s:wizard-work/null/%s" % (head, f))
if blob.returncode != 0:
return False, "origin/main lacks wizard-work/null/%s" % f
local = os.path.join(MYDIR, f)
if os.path.isfile(local):
with open(local, encoding="utf-8") as fh:
if fh.read() != blob.stdout:
return False, "%s on disk != origin/main's blob" % f
return True, "%s by null (%s) is an ancestor of origin/main %s; its tree matches the disk" % (
commit[:8], subject, head[:8])
def main(): def main():
# --- 1. presence / compile / API -------------------------------------- # --- 1. presence / compile / API --------------------------------------
for fn in NEED: for fn in NEED:
check("artifact present: " + fn, os.path.isfile(os.path.join(MYDIR, fn))) check("artifact present: " + fn, os.path.isfile(os.path.join(MYDIR, fn)))
src = open(os.path.join(MYDIR, "wizard.py"), encoding="utf-8").read() src = open(os.path.join(MYDIR, "wizard.py"), encoding="utf-8").read()
check("wizard.py compiles", _compiles(src, "wizard.py")) ok_compile = _compiles(src, "wizard.py")
check("wizard.py compiles", ok_compile)
ns = {"__name__": "wizard_module", "__file__": os.path.join(MYDIR, "wizard.py")} ns = {"__name__": "wizard_module", "__file__": os.path.join(MYDIR, "wizard.py")}
if _compiles(src, "wizard.py"): if ok_compile:
exec(compile(src, "wizard.py", "exec"), ns) exec(compile(src, "wizard.py", "exec"), ns)
check("API: craft exists", callable(ns.get("craft"))) check("API: craft exists", callable(ns.get("craft")))
check("API: render exists", callable(ns.get("render"))) check("API: render exists", callable(ns.get("render")))
check("API: parse_log exists", callable(ns.get("parse_log")))
check("API: VERDICT/CHECK markers exist", "VERDICT:" in src and "CHECK:" in src) check("API: VERDICT/CHECK markers exist", "VERDICT:" in src and "CHECK:" in src)
# --- 2. craft() / render() are pure in their arguments ----------------- # --- 2. craft() is pure in its arguments ------------------------------
try: try:
args = ("t", "a", "L", "deadbeef", "null", "2026-10-24 00:00 UTC") args = ("t", "a", "L", "deadbeef", "null", "2026-10-24 00:00 UTC")
v1, c1, _ = ns["craft"](*args) v1, c1, _ = ns["craft"](*args)
@@ -168,73 +130,87 @@ def main():
check("craft() deterministic in its stamp argument", False, check("craft() deterministic in its stamp argument", False,
"%s: %s" % (type(e).__name__, e)) "%s: %s" % (type(e).__name__, e))
# --- 3. binding: the declared commit's blob IS the log on disk ---------- # --- 3. parse the log --------------------------------------------------
log_path = os.path.join(MYDIR, LOGNAME) log_path = os.path.join(MYDIR, LOGNAME)
disk = open(log_path, encoding="utf-8").read() if os.path.exists(log_path) else "" disk = open(log_path, encoding="utf-8").read() if os.path.exists(log_path) else ""
fields = dict(ns["parse_log"](disk)) if callable(ns.get("parse_log")) else {} fields = dict(ns["parse_log"](disk)) if callable(ns.get("parse_log")) else {}
lane = fields.get("lane", "") lane = fields.get("lane", "")
area = fields.get("target area", "") area = fields.get("target area", "")
operator = fields.get("operator", "null") operator = fields.get("operator", "null")
task = fields.get("task", "")
commit = fields.get("base commit", "") commit = fields.get("base commit", "")
stamp = fields.get("stamp", "") stamp = fields.get("stamp", "")
rendered = None
try:
rendered = ns["render"](lane, area, lane, commit, operator, stamp)
except Exception: # noqa: BLE001
pass
check("log declares a base commit SHA", bool(commit), repr(commit)) check("log declares a base commit SHA", bool(commit), repr(commit))
obj = git("cat-file", "-t", commit) if commit else None obj = git("cat-file", "-t", commit) if commit else None
check("base commit resolves as a git object", check("base commit resolves as a git object",
bool(obj and obj.returncode == 0 and obj.stdout.strip() == "commit"), bool(obj and obj.returncode == 0 and obj.stdout.strip() == "commit"),
(obj.stdout.strip() if obj else "no sha") or (obj.stderr.strip() if obj else "")) (obj.stdout.strip() if obj else "no sha") or (obj.stderr.strip() if obj else ""))
head = _remote_main()
check("remote main is reachable", bool(head), head or "ls-remote returned nothing")
if commit and obj and obj.returncode == 0: if commit and obj and obj.returncode == 0:
author = git("show", "-s", "--format=%an", commit).stdout.strip() author = git("show", "-s", "--format=%an", commit).stdout.strip()
check("declared commit is authored by null", author == "null", author) check("declared commit is authored by null", author == "null", author)
blob = git("show", "%s:%s" % (commit, LOGPATH)) if head:
if blob.returncode != 0: anc = git("merge-base", "--is-ancestor", commit, head)
check("log on disk == git blob of the declared commit", False, check("declared commit is an ancestor of the remote main",
"git show failed: " + blob.stderr.strip()[:120]) anc.returncode == 0,
elif disk == blob.stdout: "%s %s an ancestor of %s" % (commit[:8],
check("log on disk == git blob of the declared commit", True, "is" if anc.returncode == 0 else "is NOT",
"%d bytes, byte-identical" % len(disk.encode())) head[:8]))
else: else:
check("log on disk == git blob of the declared commit", False, check("declared commit is an ancestor of the remote main", False, "no remote head")
"%d bytes on disk vs %d in the commit" % (len(disk.encode()), len(blob.stdout.encode())))
_name_differing_line(commit, disk)
else: else:
check("declared commit is authored by null", False, "no commit to read") check("declared commit is authored by null", False, "no commit to read")
check("log on disk == git blob of the declared commit", False, "no commit to read") check("declared commit is an ancestor of the remote main", False, "no commit to read")
check("fresh render with the log's stamp == log", # --- 4. the named commit carries the work bytes ------------------------
rendered is not None and rendered == disk, if commit and obj and obj.returncode == 0:
"render() round-trip, byte-for-byte" if rendered == disk for p in WORK_FILES:
else "render() unavailable or differs") blob = git("show", "%s:%s" % (commit, p), binary=True)
local = os.path.join(REPO, p)
disk_b = open(local, "rb").read() if os.path.isfile(local) else b""
if blob.returncode != 0:
check("named commit carries %s" % p, False,
"git show failed: " + blob.stderr.strip()[:100])
else:
check("named commit carries %s" % p, blob.stdout == disk_b,
("%d bytes, byte-identical" % len(disk_b)) if blob.stdout == disk_b
else "%d in commit vs %d on disk" % (len(blob.stdout), len(disk_b)))
else:
for p in WORK_FILES:
check("named commit carries %s" % p, False, "no commit to read")
# --- 4. shape of the log ----------------------------------------------- # --- 5. the entry itself is on the remote ------------------------------
if head:
rb = git("show", "%s:%s" % (head, LOGPATH))
ok = rb.returncode == 0 and rb.stdout == disk
check("entry bytes are the blob on the remote main", ok,
("%d bytes, byte-identical" % len(disk.encode())) if ok
else ("git show failed: " + rb.stderr.strip()[:100]) if rb.returncode != 0
else "%d on remote vs %d on disk" % (len(rb.stdout.encode()), len(disk.encode())))
else:
check("entry bytes are the blob on the remote main", False, "no remote head")
# --- 6. render() round-trip with the log's own stamp -------------------
try:
rendered = ns["render"](task, area, lane, commit, operator, stamp)
check("fresh render with the log's stamp == log", rendered == disk,
"render() round-trip, byte-for-byte" if rendered == disk else "render() differs")
except Exception as e: # noqa: BLE001
check("fresh render with the log's stamp == log", False,
"%s: %s" % (type(e).__name__, e))
# --- 7. shape of the log -----------------------------------------------
nv = len(re.findall(r"(?m)^VERDICT:", disk)) nv = len(re.findall(r"(?m)^VERDICT:", disk))
nc = len(re.findall(r"(?m)^CHECK:", disk)) nc = len(re.findall(r"(?m)^CHECK:", disk))
check("log has exactly one VERDICT:", nv == 1, "found %d" % nv) check("log has exactly one VERDICT:", nv == 1, "found %d" % nv)
check("log has exactly one CHECK:", nc == 1, "found %d" % nc) check("log has exactly one CHECK:", nc == 1, "found %d" % nc)
check("log carries its own stamp", bool(stamp), repr(stamp)) check("log carries its own stamp", bool(stamp), repr(stamp))
# --- 5. the commit is really on the REMOTE main ------------------------ # --- 8. self-run: a child really spawned and echoed the nonce ----------
ok, detail = _remote_ok(commit)
check("commit pushed to origin/main", ok, detail)
# --- 6. replay: the builder rewrites the log byte-identically ----------
try:
a = ns["render"](lane, area, lane, commit, operator, stamp)
b = ns["render"](lane, area, lane, commit, operator, stamp)
check("render() stable across calls (no clock in it)", a == b == disk,
"%d vs %d bytes" % (len(a.encode()), len(b.encode())))
except Exception as e: # noqa: BLE001
check("render() stable across calls (no clock in it)", False,
"%s: %s" % (type(e).__name__, e))
# --- 7. self-run: a child really spawned and echoed the nonce ----------
n = uuid.uuid4().hex n = uuid.uuid4().hex
child = _self_run(n) child = _self_run(n)
if child is None: if child is None:
+73 -50
View File
@@ -1,27 +1,33 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""null standup entry — Codeforge lane. """null standup entry -- Codeforge lane.
Rebuilds the log from parameters, never from the wall clock: Rebuilds the log from parameters, never from the wall clock:
python3 wizard.py # writes wizard.log.md next to this file python3 wizard.py # writes wizard.log.md next to this file
python3 check.py # exit 0 == artifact is real, exit 1 == broken python3 check.py # exit 0 == artifact is real, exit 1 == broken
Determinism: craft() takes its stamp as a required parameter, so its output is Determinism. craft() takes its stamp as a required parameter, so its output is
a function of its arguments. main() stamps only when the log has no stamp yet; a function of its arguments; render() never reads the clock or the filesystem.
replaying a log whose stamp is already current rewrites the file byte-identically. Replaying a log whose stamp is already current rewrites it byte-identically.
The entry names the commit whose tree contains *these exact bytes* -- found by Binding -- and why it is NOT "the commit whose tree holds these bytes".
searching main for a commit whose blob of this file is byte-identical to what is The entry names a commit SHA, so its own bytes can never be the blob of the
on disk, never HEAD and never the newest commit that merely touches the path. commit it names: that blob would have to contain the very SHA that the blob
Two traps that naive versions of this fall into: itself determines. That is a hash fixed point; no commit satisfies it, and a
* naming HEAD goes stale the moment a teammate commits, so the gate stays gate demanding it is unsatisfiable and reads red forever (the failure this
green for a tree main no longer has; replaces). The satisfiable binding names the commit that carries the WORK --
* naming the newest commit that touches the path goes stale the moment the log wizard.py and check.py -- and verifies the entry itself separately, on the
changes without being committed, which is exactly the state that produced a remote:
green gate over a stale artifact.
If no such commit exists, the gate refuses to pass.
Import-free by design — check.py exec()s this file with no __file__ in scope — * the named commit is by null and is an ancestor of the remote main;
* the named commit's blobs of wizard.py and check.py are byte-identical to
the files on disk;
* the entry's own bytes are the blob of wizard.log.md on the remote main.
Nothing here is self-referential: the work files do not contain the SHA, and
the entry is committed after the work commit it names.
Import-free by design -- check.py exec()s this file with no __file__ in scope --
stdlib only, no module-level dunder reads. stdlib only, no module-level dunder reads.
""" """
import os import os
@@ -31,30 +37,28 @@ from datetime import datetime, timezone
LANE = "Codeforge - hard coding and agentic reasoning" LANE = "Codeforge - hard coding and agentic reasoning"
REPO = "/root/troupe-standup" REPO = "/root/troupe-standup"
LOGPATH = "wizard-work/null/wizard.log.md"
HERE = "/root/troupe-standup/wizard-work/null" HERE = "/root/troupe-standup/wizard-work/null"
LOGNAME = "wizard.log.md" LOGNAME = "wizard.log.md"
LOGPATH = "wizard-work/null/" + LOGNAME
STAMP_FMT = "%Y-%m-%d %H:%M UTC" STAMP_FMT = "%Y-%m-%d %H:%M UTC"
STAMP_RE = re.compile(r"self-verified at [0-9-]+ [0-9:]+ UTC") STAMP_RE = re.compile(r"self-verified at [0-9-]+ [0-9:]+ UTC")
TASK = "bind the standup entry to the commit whose tree holds these bytes" TASK = "bind the standup entry to the commit that carries its work bytes"
AREA = "wizard-work/null" AREA = "wizard-work/null"
OPERATOR = "null" OPERATOR = "null"
WORK = [ WORK = [
"wizard.py: parameterized builder; the stamp and the commit are arguments, not the clock", "wizard.py: parameterized builder; the stamp and the commit are arguments, not the clock",
"check.py: gate binds the log to the commit whose blob is byte-identical, not to HEAD", "check.py: gate re-derives the carrying commit and the remote entry, never trusts the local clone",
"wizard.log.md: self-describing entry carrying its own stamp and its carrying commit", "wizard.log.md: self-describing entry naming the commit that carries wizard.py and check.py",
] ]
EVIDENCE = [ EVIDENCE = [
("log on disk == git blob of the commit it names", "measured", ("the named commit is by null and is an ancestor of the REMOTE main", "measured",
"check.py: byte comparison, names the differing line"), "check.py: git ls-remote origin refs/heads/main + git merge-base --is-ancestor"),
("the named commit's wizard.py and check.py are byte-identical to disk", "measured",
"check.py: git show <sha>:path vs the file on disk, byte comparison"),
("the entry's bytes are the blob on the REMOTE main", "measured",
"check.py: git ls-remote + git show <remote>:wizard-work/null/wizard.log.md"),
("fresh render with the log's own stamp == log", "measured", ("fresh render with the log's own stamp == log", "measured",
"check.py: render() round-trip, no clock in the output"), "check.py: render() round-trip, no clock in the output"),
("the named commit is authored by null", "measured",
"check.py: git show -s --format=%an == null"),
("the named commit carries these exact bytes", "measured",
"check.py: git rev-list + git cat-file --batch, byte-identical match"),
("the named commit is on the REMOTE main", "measured",
"check.py: git ls-remote origin refs/heads/main, not the local clone"),
("craft() deterministic in its stamp argument", "measured", ("craft() deterministic in its stamp argument", "measured",
"check.py: same args -> same bytes; different stamp -> different verdict"), "check.py: same args -> same bytes; different stamp -> different verdict"),
] ]
@@ -68,8 +72,12 @@ def parse_log(text):
for key in ("lane", "operator", "target area", "base commit", "log"): for key in ("lane", "operator", "target area", "base commit", "log"):
if s.startswith("- " + key + ": "): if s.startswith("- " + key + ": "):
fields[key] = s[len("- " + key + ": "):] fields[key] = s[len("- " + key + ": "):]
if s.startswith("VERDICT: ") and "self-verified at " in s: if s.startswith("VERDICT: "):
fields["stamp"] = s.split("self-verified at ", 1)[1].rstrip(" .") body = s[len("VERDICT: "):]
if " - " in body:
fields["task"] = body.split(" - ", 1)[0]
if "self-verified at " in body:
fields["stamp"] = body.split("self-verified at ", 1)[1].rstrip(" .")
return fields return fields
@@ -135,24 +143,39 @@ def _git(*args, binary=False):
def head_sha(): def head_sha():
"""HEAD, for orientation only. Never used as the entry's base commit.""" """HEAD, for anyone who wants the local tip."""
return _git("rev-parse", "HEAD").stdout.strip() or "unresolved" return _git("rev-parse", "HEAD").stdout.strip() or ""
def carrying_commit(text): def _main_shas(path):
"""The commit whose tree contains exactly `text`, searching main's history. """Commits on origin/main that ever touched `path`, newest first."""
r = _git("rev-list", "origin/main", "--", path)
Walks every commit that touched this file and keeps the first whose blob of
the file is byte-identical to `text`. Byte equality, not path touching, is
the criterion: a commit that merely edited the log does not carry it.
"""
r = _git("rev-list", "origin/main", "--", LOGPATH)
if r.returncode != 0 or not r.stdout.strip(): if r.returncode != 0 or not r.stdout.strip():
return "" return []
want = text.encode() return r.stdout.split()
for sha in r.stdout.split():
blob = _git("show", "%s:%s" % (sha, LOGPATH), binary=True)
if blob.returncode == 0 and blob.stdout == want: def _blob_matches(sha, path):
"""True iff commit `sha`'s blob at `path` is byte-identical to the disk file."""
local = os.path.join(REPO, path)
if not os.path.isfile(local):
return False
with open(local, "rb") as fh:
want = fh.read()
blob = _git("show", "%s:%s" % (sha, path), binary=True)
return blob.returncode == 0 and blob.stdout == want
def commit_carrying(paths):
"""The newest commit on origin/main whose blobs for every path equal disk.
That is the commit the entry names: it is the one that carries the exact
work bytes, so the entry cannot name a commit that does not hold them.
Returns "" when no such commit exists (the entry is not committed yet).
"""
cands = _main_shas(paths[0])
for sha in cands:
if all(_blob_matches(sha, p) for p in paths):
return sha return sha
return "" return ""
@@ -162,14 +185,14 @@ def main():
stamp = parse_log(open(path, encoding="utf-8").read()).get("stamp") if os.path.exists(path) else None stamp = parse_log(open(path, encoding="utf-8").read()).get("stamp") if os.path.exists(path) else None
if not stamp: if not stamp:
stamp = stamp_now() # first build only; replays reuse the committed stamp stamp = stamp_now() # first build only; replays reuse the committed stamp
text = render(TASK, AREA, LANE, "", OPERATOR, stamp)
commit = carrying_commit(text) if text else "" sha = commit_carrying(["wizard-work/null/wizard.py", "wizard-work/null/check.py"])
if not commit: if not sha:
commit = "unresolved" # the gate refuses to pass on this sha = "unresolved" # the gate refuses to pass on this
text = render(TASK, AREA, LANE, commit, OPERATOR, stamp) text = render(TASK, AREA, LANE, sha, OPERATOR, stamp)
with open(path, "w", encoding="utf-8") as fh: with open(path, "w", encoding="utf-8") as fh:
fh.write(text) fh.write(text)
verdict, check, _ = craft(TASK, AREA, LANE, commit, OPERATOR, stamp) verdict, check, _ = craft(TASK, AREA, LANE, sha, OPERATOR, stamp)
print(verdict) print(verdict)
print(check) print(check)