The Principia Machina/TPC-PY/tpc hunk.py: Difference between revisions
Appearance
TPC-PY source tpc_hunk.py (0.1.0), SHA-256 b1662188a9ae9340; conformed TPS 0.3.0; PROPOSED, not declared (CO-8) |
m 1 revision imported |
||
(No difference)
| |||
Latest revision as of 04:37, 28 September 2026
"""tpc_hunk 0.1.0 (DRAFT, pending D151): hunk_apply, the page write of a
PATCH falcon's approved hunks.
Reference implementation, Python standard library only. DATA for landing
round 8 of branch tpm_project_closeout (the falcon speculation 0.1.0
section 7's approval-form step and section 8's signature; PMP-TPM 0.12.0
FALCONS, APPROVAL AND APPLICATION; record D151.1 (b), (g)); not a
declared TPC-PY version and not TPX code. A pure function of its
arguments. Every refused argument raises ValueError with a short fixed
message. render_hunk() gives the canonical text the PHP residence
(tpc_hunk.php) reproduces byte for byte. Kept in its own module so that
tpc_falcon 0.1.1's source_match amendment (agent BC) and this function
never touch one file.
hunk_apply(base_text, hunks) -> dict
base_text: the target page's text at the falcon's base revision, a
string (TPX has already refused BASE MOVED, D151.1 (g)).
hunks: the approved hunks, a list of objects {old, new} (the optional
keys n, anchor and count of the landing rounds' hunk files are
accepted and read by nothing), old and new strings; applied in list
order. Anything else raises ValueError("hunks"); a base that is not a
string raises ValueError("base").
Result: {status: OK, applied: the hunk count, sha256: the SHA-256 of
the result's UTF-8, text: the result}, or {status: REFUSED, reason,
hunk: the 1-based index of the hunk refused}. TPX saves the OK text
as the approver's own revision and reads back its SHA-1 (D151.1 (b));
on REFUSED nothing is saved.
Rule (the falcon speculation 8, hunk_apply: "each old string occurs
exactly once in the base and no two hunks overlap, else REFUSED;
applied in order"):
HK1 EMPTY. An old string that is empty occurs at every position, never
exactly once: REFUSED, reason EMPTY.
HK2 EXACTLY ONCE. Each old string is located in the BASE TEXT, exactly
as given (no normalization: the approved text was drawn from the
same base by exact replacement, D151.1 (b)); every start position
is counted, overlapping occurrences included, so "aa" in "aaa"
occurs twice. None: REFUSED, reason ABSENT; two or more: REFUSED,
reason MULTIPLE.
HK3 NO OVERLAP. The located ranges [start, start + len(old)) of any two
hunks are disjoint; adjacent ranges (one ending where the next
begins) do not overlap. A hunk whose range meets an earlier hunk's
range: REFUSED, reason OVERLAP.
HK4 APPLICATION. Each old string is replaced by its new string at its
located position; the ranges being disjoint in the base, the
result is the same whichever hunk is applied first, and equals the
sequential application of the list. Reading taken by delegation
2026-09-26 (spec note PD-OC-3): "in order" names the sequence of
application, not the positions: the hunk list need not be sorted
by position (the landing rounds' hunk sets are not, and every one
of them replays under this rule). The alternative, REFUSED with a
reason ORDER when positions do not ascend with the list, is in the
spec note.
HK5 An empty hunk list gives OK with the base unchanged (spec note
PD-OC-4; alternative: REFUSED, reason NONE). A hunk whose new
string equals its old string is a no-op and is applied.
The first hunk that fails HK1-HK3 in list order names the refusal;
every hunk is located before any is applied, so a refusal changes
nothing.
"""
import hashlib
VERSION = "0.1.0"
REASONS = ("EMPTY", "ABSENT", "MULTIPLE", "OVERLAP")
def _esc(s):
"""Render escape: "|" and "\\" backslashed; C0 controls and DEL as
\\xHH; every other character as it is."""
out = []
for ch in s:
o = ord(ch)
if ch == "|" or ch == "\\":
out.append("\\" + ch)
elif o < 0x20 or o == 0x7F:
out.append("\\x%02x" % o)
else:
out.append(ch)
return "".join(out)
def _is_text(s):
if type(s) is not str:
return False
for ch in s:
if 0xD800 <= ord(ch) <= 0xDFFF:
return False
return True
def _check(base_text, hunks):
if not _is_text(base_text):
raise ValueError("base")
if type(hunks) is not list:
raise ValueError("hunks")
for h in hunks:
if type(h) is not dict or "old" not in h or "new" not in h:
raise ValueError("hunks")
for k in h:
if k not in ("old", "new", "n", "anchor", "count"):
raise ValueError("hunks")
if not _is_text(h["old"]) or not _is_text(h["new"]):
raise ValueError("hunks")
def count_occurrences(text, needle):
"""Every start position of a non-empty needle, overlapping included."""
n = 0
i = text.find(needle)
while i != -1:
n += 1
i = text.find(needle, i + 1)
return n
def hunk_apply(base_text, hunks):
_check(base_text, hunks)
located = []
for idx, h in enumerate(hunks):
old = h["old"]
if old == "":
return {"status": "REFUSED", "reason": "EMPTY", "hunk": idx + 1}
c = count_occurrences(base_text, old)
if c == 0:
return {"status": "REFUSED", "reason": "ABSENT", "hunk": idx + 1}
if c > 1:
return {"status": "REFUSED", "reason": "MULTIPLE",
"hunk": idx + 1}
start = base_text.find(old)
end = start + len(old)
for s2, e2 in located:
if start < e2 and s2 < end:
return {"status": "REFUSED", "reason": "OVERLAP",
"hunk": idx + 1}
located.append((start, end))
order = sorted(range(len(hunks)), key=lambda i: located[i][0])
pieces = []
cur = 0
for i in order:
start, end = located[i]
pieces.append(base_text[cur:start])
pieces.append(hunks[i]["new"])
cur = end
pieces.append(base_text[cur:])
text = "".join(pieces)
return {"status": "OK", "applied": len(hunks),
"sha256": hashlib.sha256(text.encode("utf-8")).hexdigest(),
"text": text}
def render_hunk(d):
if d["status"] == "REFUSED":
return "REFUSED|%s|%d" % (d["reason"], d["hunk"])
return "OK|%d|%s\ntext|%s" % (d["applied"], d["sha256"], _esc(d["text"]))
FNS = ("hunk",)
def run_case(fn, args):
"""One corpus case: the render, or "ERROR:" and the message."""
if fn not in FNS:
raise ValueError("fn")
try:
return render_hunk(hunk_apply(args["base"], args["hunks"]))
except ValueError as ex:
return "ERROR:" + str(ex)