[FIX] PENDING-164 (c)+(d): prior-art search, one implementation, two surfaces
Steward-authorized in session. prior-art.py searches commit messages across every owned repo with NO count window and reports the register's mention count beside it; the executor runs it as a CLI (d) and governance-mcp.py exposes it as prior_art (c). One implementation on purpose — a value computed twice on two sides of a boundary is how the parties end up with different answers. Verified on the case that motivated the item: 'LFS' returns 20 commits including 0677e8a and95760ff, both past repo_activity's 100-commit floor, one of them in dotfiles which is not in REPOS. The positive control forced the enumeration to be COMPUTED from remote ownership rather than copied from REPOS, or95760ffwould have been unreachable and the control would have failed. Had this existed this morning, one command before filing PENDING-163 would have returned 0677e8a and 400c054. ⚠ Its first run returned zero and the control caught it: sh() discarded stdout on non-zero exit, and find over $HOME exits 1 from 154 unreadable Library dirs while printing all 37 repos. Third false-zero of the day, first one caught before being believed — the difference is that the jurist pre-specified what it must return. AMENDMENT 1's census: mechanical half runs (661 candidates, narrowed to 270), interpretive half does not. Identifying WHICH mechanism a commit decided about is interpretation, not extraction. Limit declared rather than a column manufactured. The backlog is NOT censused and no number here is one. Extending the read-only guarantee to delegates found a pre-existing hole: bare .replace flagged str.replace() (why it had never been extended), and wake-digest, a delegate since before today, was never covered. Its only real mutation is emit_brief(), its hook role, unreachable from any tool. Now a declared exemption per delegate, so a new mutating function fails until named. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NvZAKSf9aqratbqHbU9LK5
This commit is contained in:
co-authored by
Claude Opus 5
parent
46aa3d15a2
commit
b28cc03737
+31
@@ -6079,3 +6079,34 @@ The item presented (c) as *keep the backup* **or** *remove the vector*. The juri
|
||||
**Recommendation, revised: corrected-(d) first, then (b) once (d) is live, and (c) available on the archive route whenever the steward wants the vector gone.** (c) is no longer gated on retiring the backup.
|
||||
|
||||
**Awaiting:** Steward authorization. Nothing here is built; this corrects a specification before it is implemented, which is the cheapest point at which this correction could have landed.
|
||||
|
||||
### PENDING-164 — BUILD RECORD + AMENDMENT 1 result: (c) and (d) built; the census's second half is not mechanical
|
||||
**Date:** 2026-08-26
|
||||
**Authorization:** steward, in session — *"Pending 164 c + d authorized with the amendment."*
|
||||
|
||||
**(c) and (d) are built, as ONE implementation with two surfaces.** `scripts/prior-art.py` searches commit messages across every owned repo with **no count window**, and reports the register's mention count beside it. The executor runs it as a CLI (**(d)**, the pre-proposal check); `governance-mcp.py` exposes it as `prior_art` (**(c)**, the jurist's reach). One implementation deliberately — a value computed twice on two sides of a boundary is how the two parties end up with different answers.
|
||||
|
||||
**The finding it looks for is the ASYMMETRY**, not the hits: commits mention it, the register does not. That is a decision taken in a repo and never routed into the record.
|
||||
|
||||
**Verified against the case that motivated the item.** Run on `LFS` it returns **20 commits including `0677e8a` and `95760ff`** — both beyond `repo_activity`'s 100-commit floor, one of them in `dotfiles`, which is not in `REPOS` at all. ⚠ **The positive control forced the enumeration**: had owned repos been copied from `REPOS`, `95760ff` would have been unreachable and the control would have failed. Repos are now **computed from remote ownership**, not hand-listed.
|
||||
|
||||
⚠ **Had this existed this morning, one command before filing PENDING-163 would have returned `0677e8a` and `400c054`. The entire afternoon's detour was one command away.**
|
||||
|
||||
**⚠ The instrument's first run returned zero, and the control caught it.** `sh()` discarded stdout on a non-zero exit; `find` over `$HOME` exits 1 because 154 directories under `Library` are unreadable — **while printing all 37 repos to stdout.** Every search returned nothing. Without the control that is a clean, confident *"no prior art"* for every term ever queried. **This is the third false-zero of the day and the first one a control caught before it was believed** — the difference from the census's zsh zero is entirely that the jurist pre-specified what the instrument must return.
|
||||
|
||||
**AMENDMENT 1's census: the mechanical half runs; the interpretive half does not, and that IS the result.**
|
||||
|
||||
| verb set | candidates |
|
||||
|---|---|
|
||||
| first, incl. "remove"/"replace with"/"no longer" | **661** |
|
||||
| narrowed to strong retirement/adoption forms | **270** (243 outside `dotfiles`) |
|
||||
|
||||
Neither number is a census result — both are haystacks. The specification has two halves: grep the verbs, **then check each hit against the register**. The first is mechanical. The second requires reading each commit to identify *which mechanism it decided about*, and that is interpretation, not extraction. **The same shape as PENDING-151 step 1, where propositions could not be extracted mechanically either — and, as there, the honest move is to declare the limit rather than manufacture the column.**
|
||||
|
||||
**⇒ The backlog is NOT censused, and no number here should be read as one.** What exists is a candidate list of 270, unclassified. Classifying it is a reading task of a few hours, and it is proposed as such rather than smuggled in as a result. **The forward-looking halves — (c) and (d) — are complete and need nothing further.**
|
||||
|
||||
**Files:** `scripts/prior-art.py` (new), `scripts/governance-mcp.py` (+`prior_art`, +9 controls).
|
||||
|
||||
⚠ **The read-only guarantee was extended, and doing so found a pre-existing hole.** `governance-mcp.py` proves read-only-ness by AST **over itself**; adding a delegate put code outside that proof. Extending it to delegates surfaced (a) a **false-positive class** — bare `.replace` flagged `str.replace()`, which is why the guarantee had never been extended past one file — and (b) that `wake-digest.py`, a delegate **since before today**, was never covered. Its only real mutation is `emit_brief()`, its SessionStart-hook role, unreachable from any tool. Now handled by **declared exemption per delegate**, so a new mutating function fails until someone names it and says why — the same shape as PENDING-165's allowlist, and for the same reason.
|
||||
|
||||
**Awaiting:** nothing on (c)/(d). The 270-candidate classification pass is unscheduled and unclaimed.
|
||||
|
||||
+119
-1
@@ -63,6 +63,7 @@ def _load(mod_name, filename):
|
||||
|
||||
|
||||
wd = _load("wake_digest", "wake-digest.py") # the single definition of "open item"
|
||||
pa = _load("prior_art", "prior-art.py") # PENDING-164 (c): commit history, no window
|
||||
|
||||
# ---- the enumerated domain: keys, never paths -------------------------------
|
||||
FILES = {
|
||||
@@ -428,6 +429,53 @@ def t_pair(args):
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
# ── PENDING-164 (c) ───────────────────────────────────────────────────────────────
|
||||
# repo_activity caps at 100 commits. At chamber-library's rate that floor sat five weeks
|
||||
# short of 0677e8a — the commit retiring LFS — so when the jurist recommended adopting
|
||||
# LFS on 2026-08-26, NO instrument available to it could have reached the refutation.
|
||||
# 'Search prior art before proposing' was not a rule the jurist could follow.
|
||||
#
|
||||
# This removes the asymmetry rather than papering over it: one implementation
|
||||
# (prior-art.py), two consumers — the executor's CLI and this tool — so the answer cannot
|
||||
# differ by surface. It returns the substrate, not testimony about it.
|
||||
def t_prior_art(args):
|
||||
"""Commit-message history for a named mechanism, across every owned repo, unbounded."""
|
||||
term = (args.get("term") or "").strip()
|
||||
if not term:
|
||||
return "ERROR: term is required (the mechanism's name, e.g. 'LFS', 'submodule')."
|
||||
if len(term) < 2:
|
||||
return "ERROR: term too short to be discriminating."
|
||||
ok, notes, _ = pa.controls()
|
||||
hits = pa.search_commits(term)
|
||||
reg = pa.register_mentions(term)
|
||||
out = []
|
||||
if not ok:
|
||||
out.append("⚠ INSTRUMENT NOT VERIFIED — result unestablished. "
|
||||
+ "; ".join(notes))
|
||||
out.append("")
|
||||
out.append(f"PRIOR ART: {term!r}")
|
||||
out.append(f" commits mentioning it : {len(hits)} (all branches, NO count window)")
|
||||
out.append(f" register mentions : {reg} (PENDING, PENDING-archive, REVIEWED)")
|
||||
out.append("")
|
||||
for repo, sha, date, subj in sorted(hits, key=lambda h: h[2])[:60]:
|
||||
out.append(f" {date} {repo:32} {sha} {subj[:72]}")
|
||||
if len(hits) > 60:
|
||||
out.append(f" … {len(hits) - 60} further commit(s) not listed.")
|
||||
out.append("")
|
||||
if hits and reg == 0:
|
||||
out.append(" \u26a0 FINDING — PENDING-164's condition exactly: this mechanism has a")
|
||||
out.append(" history in the repos and NO trace in the authorization record. Whatever")
|
||||
out.append(" was decided about it was decided in a commit message. Read those")
|
||||
out.append(" commits before proposing anything about it.")
|
||||
elif hits:
|
||||
out.append(" Both surfaces carry it. A ruling can post-date the commit that")
|
||||
out.append(" motivated it, or precede the one that undid it — read both.")
|
||||
else:
|
||||
out.append(" No prior art. \u26a0 Weak absence: it means no COMMIT MESSAGE names this")
|
||||
out.append(" term, not that nothing was decided about it.")
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
TOOLS = [
|
||||
("governance_state", t_state,
|
||||
"Current governance state, computed live: every open authorization item with its "
|
||||
@@ -474,6 +522,16 @@ TOOLS = [
|
||||
"Full governance-drift-check output: claims in CLAUDE.md the substrate contradicts. "
|
||||
"Detection only — correcting doctrine requires steward authorization.",
|
||||
{"type": "object", "properties": {}}),
|
||||
("prior_art", t_prior_art,
|
||||
"Commit-message history for a named mechanism across every owned repo, with NO "
|
||||
"commit-count window, plus whether the authorization register mentions it. Use this "
|
||||
"BEFORE proposing or ruling on any named mechanism — repo_activity caps at 100 "
|
||||
"commits and that floor has already hidden a decision this system had made. Commits "
|
||||
"with zero register mentions is the finding, not the noise.",
|
||||
{"type": "object", "properties": {
|
||||
"term": {"type": "string",
|
||||
"description": "The mechanism's name, e.g. 'LFS', 'submodule', 'worktree'."}},
|
||||
"required": ["term"]}),
|
||||
("repo_activity", t_repo,
|
||||
"Branch, uncommitted-file status and recent commits for one of the active repos.",
|
||||
{"type": "object", "properties": {
|
||||
@@ -550,8 +608,16 @@ def write_calls(src):
|
||||
duly found all of them, in its own definition. That is the day's recurring shape:
|
||||
an instrument whose domain includes itself. The AST sees calls, not characters."""
|
||||
import ast
|
||||
MUTATORS = {"remove", "unlink", "rename", "replace", "rmdir", "mkdir", "makedirs",
|
||||
MUTATORS = {"remove", "unlink", "rename", "rmdir", "mkdir", "makedirs",
|
||||
"chmod", "truncate", "write", "writelines", "write_text", "write_bytes"}
|
||||
# `replace` is NOT in MUTATORS as a bare attribute: str.replace() is ubiquitous and
|
||||
# flagging it made this check unusable on any file that manipulates text — which is
|
||||
# why it had never been extended past this file. os.replace/Path.replace ARE caught,
|
||||
# by qualified name below. Narrowed 2026-08-26 when extending the guarantee to
|
||||
# delegates surfaced three false positives in wake-digest.py (lines 142, 150, 888,
|
||||
# every one a string replace) alongside one real write.
|
||||
QUALIFIED = {("os", "replace"), ("shutil", "move"), ("shutil", "rmtree"),
|
||||
("shutil", "copy"), ("shutil", "copy2"), ("shutil", "copytree")}
|
||||
out = []
|
||||
for n in ast.walk(ast.parse(src)):
|
||||
if not isinstance(n, ast.Call):
|
||||
@@ -565,6 +631,9 @@ def write_calls(src):
|
||||
out.append(f"open(mode={mode!r}) at line {n.lineno}")
|
||||
elif isinstance(f, ast.Attribute) and f.attr in MUTATORS:
|
||||
out.append(f"{f.attr}() at line {n.lineno}")
|
||||
elif (isinstance(f, ast.Attribute) and isinstance(f.value, ast.Name)
|
||||
and (f.value.id, f.attr) in QUALIFIED):
|
||||
out.append(f"{f.value.id}.{f.attr}() at line {n.lineno}")
|
||||
return out
|
||||
|
||||
|
||||
@@ -693,6 +762,19 @@ def selftest():
|
||||
"2026-08-05; this control goes red if a header is ever hidden again]",
|
||||
"MATCHES OUTSIDE ANY ITEM" not in t_search({"query": "the"}))
|
||||
|
||||
print("\nprior_art — PENDING-164 (c): the window that hid 0677e8a:")
|
||||
chk("prior_art returns the commit repo_activity's 100-window could not reach "
|
||||
"[0677e8a, 2026-06-05, five weeks past the floor]",
|
||||
"0677e8a" in t_prior_art({"term": "LFS"}))
|
||||
chk("prior_art reaches dotfiles, which is NOT in REPOS [95760ff]",
|
||||
"95760ff" in t_prior_art({"term": "LFS"}))
|
||||
chk("prior_art reports the register count alongside the commits "
|
||||
"[the asymmetry IS the finding]",
|
||||
"register mentions" in t_prior_art({"term": "LFS"}))
|
||||
chk("prior_art on a nonsense term reports no prior art, and calls the absence weak "
|
||||
"[negative control]",
|
||||
"No prior art" in t_prior_art({"term": "zzqqxx-not-a-real-term-9971"}))
|
||||
chk("prior_art refuses an empty term", t_prior_art({}).startswith("ERROR"))
|
||||
chk("repo_activity refuses an unlisted repo",
|
||||
t_repo({"repo": "/etc"}).startswith("ERROR: unknown repo"))
|
||||
chk("repo_activity ACCEPTS a listed repo [positive control]",
|
||||
@@ -740,6 +822,42 @@ def selftest():
|
||||
src = open(__file__, encoding="utf-8").read()
|
||||
chk("no filesystem-mutating call in this file",
|
||||
write_calls(src) == [])
|
||||
# ⚠ The guarantee is scoped to the file the AST reads. Adding prior_art (PENDING-164
|
||||
# (c)) put a DELEGATION outside that scope: t_prior_art calls into prior-art.py, whose
|
||||
# code this check never saw. A structural guarantee with a hole where it delegates is
|
||||
# the shape of every other defect in this thread — so the delegate is checked too, and
|
||||
# any future delegate must be added here or the guarantee silently narrows.
|
||||
# Each delegate must have NO mutating call, except in functions DECLARED here as
|
||||
# unreachable from this server. Declared, never inferred — the same shape as the hook
|
||||
# allowlist: a new mutating function in a delegate fails until someone names it and
|
||||
# says why. wake-digest.py is also a SessionStart hook, and emit_brief() is its hook
|
||||
# role; no tool in this file calls it.
|
||||
_delegates = {"prior-art.py": set(), "wake-digest.py": {"emit_brief"}}
|
||||
for _fn, _exempt in sorted(_delegates.items()):
|
||||
_dsrc = open(os.path.join(SCRIPTS, _fn), encoding="utf-8").read()
|
||||
_tree = __import__("ast").parse(_dsrc)
|
||||
_spans = {f.name: (f.lineno, f.end_lineno) for f in __import__("ast").walk(_tree)
|
||||
if isinstance(f, __import__("ast").FunctionDef)}
|
||||
_bad = []
|
||||
for _call in write_calls(_dsrc):
|
||||
_ln = int(_call.rsplit(" ", 1)[-1])
|
||||
_in = [n for n, (a, b) in _spans.items() if a <= _ln <= (b or a)]
|
||||
if not any(n in _exempt for n in _in):
|
||||
_bad.append(f"{_call} in {_in or ['<module level>']}")
|
||||
chk(f"DELEGATE {_fn}: no mutating call outside its declared exemptions {sorted(_exempt) or '(none)'} "
|
||||
"[the read-only guarantee must not stop at this file's edge]",
|
||||
_bad == [], )
|
||||
if _bad:
|
||||
for _b in _bad:
|
||||
print(f" {_b}")
|
||||
chk("the delegate check DOES flag an undeclared mutation [positive control — an "
|
||||
"exemption list that never refuses is not a check]",
|
||||
write_calls("import os\nos.remove('x')\n") != [])
|
||||
chk("str.replace() is NOT flagged as a mutation [negative control — it was, and that "
|
||||
"false positive is why this guarantee had never been extended]",
|
||||
write_calls("s = 'a'.replace('a','b')\n") == [])
|
||||
chk("os.replace() IS still flagged [positive control for the narrowing above]",
|
||||
write_calls("import os\nos.replace('a','b')\n") != [])
|
||||
chk("the checker DOES flag writes when present [positive control — a text search "
|
||||
"here would match its own token list, which is how the first version of this "
|
||||
"check failed]",
|
||||
|
||||
Executable
+216
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Prior-art search over commit history — PENDING-164 options (c) and (d).
|
||||
|
||||
WHY THIS EXISTS
|
||||
On 2026-06-05 the steward adopted Git LFS in chamber-library, found it a misfit,
|
||||
retired it, and rewrote seventeen commits to undo it (0677e8a). A per-repo hook
|
||||
exemption replaced it (400c054). Neither decision appears anywhere in PENDING.md,
|
||||
PENDING-archive.md or REVIEWED.md.
|
||||
|
||||
Twelve weeks later the executor filed PENDING-163 recommending a route toward LFS,
|
||||
and the jurist recommended adopting it outright. Three exchanges were spent before
|
||||
the refutation surfaced, and it surfaced by accident — the string 'pre-lfs-export'
|
||||
appeared in an unrelated directory listing.
|
||||
|
||||
The symptom was two parties reasoning toward a retired mechanism. The disease is that
|
||||
the record where such a decision is supposed to be findable does not contain it, so
|
||||
the only party who could have found it is the one with a filesystem. That is the
|
||||
asymmetry the three-party model exists to work around.
|
||||
|
||||
WHAT IT DOES
|
||||
(c) Makes the substrate REACHABLE rather than copying it: searches commit messages
|
||||
across the steward's repos, unbounded by any commit-count window, and reports
|
||||
whether the same term appears in the authorization register. Exposed to the
|
||||
jurist through governance-mcp.py, whose repo_activity caps at 100 commits — a
|
||||
floor that sat five weeks short of 0677e8a.
|
||||
|
||||
(d) Gives the executor a pre-proposal check: before any [PROPOSAL] naming a mechanism
|
||||
by name, run this and report the result. Mechanizes the discipline on the side
|
||||
that has the filesystem.
|
||||
|
||||
--census runs the one-time backward sweep (PENDING-164 AMENDMENT 1): adoption and
|
||||
retirement verbs across every owned repo, each hit checked against the register.
|
||||
|
||||
THE FINDING THIS LOOKS FOR
|
||||
Not "were there commits". The asymmetry: commits mention it, the register does not.
|
||||
That is a decision taken in a repo and never routed into the authorization record.
|
||||
|
||||
ENUMERATION IS COMPUTED, NOT HAND-HELD
|
||||
Owned repos are those whose remotes point at the steward's hosts. A hand-maintained
|
||||
list is the failure mode PENDING-108 already measured: it is correct until someone
|
||||
forgets, and nothing reports the forgetting. Note the positive control below forced
|
||||
this: 0677e8a is in chamber-library and 95760ff is in dotfiles, and dotfiles is not
|
||||
in governance-mcp.py's REPOS.
|
||||
"""
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
HOME = Path.home()
|
||||
OWNED_HOSTS = ("github.com/davidglidden", "davidglidden/", "git.skemantix.com")
|
||||
REGISTER = [HOME / "PENDING.md", HOME / "PENDING-archive.md", HOME / "REVIEWED.md"]
|
||||
|
||||
# The census's verbs. Deliberately about ADOPTION and RETIREMENT of mechanisms, not about
|
||||
# ordinary change — "fix", "update" and "refactor" would return everything and measure
|
||||
# nothing.
|
||||
# ⚠ NARROWED after the first run, and the number is recorded because it is the finding.
|
||||
# The first verb set — which included "remove", "replace with", "no longer", "switch to" —
|
||||
# returned 661 candidates across 8 repos. That is a haystack, not a census: those verbs
|
||||
# catch ordinary development. Narrowed to forms that are almost always ABOUT A MECHANISM
|
||||
# rather than about a file.
|
||||
#
|
||||
# ⚠ AND THE HONEST LIMIT, stated here rather than discovered later: the jurist's
|
||||
# specification has two halves — grep the verbs, THEN check each hit against the register.
|
||||
# The first half is mechanical and is what this does. The second requires reading each
|
||||
# commit to identify WHICH mechanism it decided about, and that is interpretation, not
|
||||
# extraction. This instrument does not do it and does not pretend to. Same shape as
|
||||
# PENDING-151 step 1, where propositions could not be extracted mechanically either.
|
||||
CENSUS_VERBS = ["retire", "retired", "retiring", "abandon", "deprecat", "migrat",
|
||||
"stop using", "move away from", "back out", "revert to",
|
||||
"no longer use", "no longer using", "roll back", "un-adopt"]
|
||||
|
||||
|
||||
def sh(cmd, cwd=None):
|
||||
"""stdout REGARDLESS of exit code.
|
||||
|
||||
⚠ Earned, not stylistic. The first form returned "" on a non-zero exit. `find` over
|
||||
$HOME exits 1 because 154 directories under Library are unreadable — while printing
|
||||
all 37 repos to stdout. So the repo list came back empty, every search returned zero,
|
||||
and the instrument would have reported "no prior art" for everything. The positive
|
||||
control caught it; without the control it was a clean, confident, wrong zero — the
|
||||
exact failure this whole item is about. git returns empty stdout when it genuinely
|
||||
fails, so nothing false is admitted by ignoring the code here."""
|
||||
try:
|
||||
r = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, timeout=90)
|
||||
return r.stdout
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
def owned_repos():
|
||||
"""Repos whose remotes point at the steward's hosts. Computed, never listed."""
|
||||
out = sh(["find", str(HOME), "-maxdepth", "5", "-type", "d", "-name", ".git"])
|
||||
repos = []
|
||||
for line in out.splitlines():
|
||||
if not line.strip():
|
||||
continue
|
||||
r = Path(line).parent
|
||||
rem = sh(["git", "-C", str(r), "remote", "-v"])
|
||||
if any(h in rem for h in OWNED_HOSTS):
|
||||
repos.append(r)
|
||||
return sorted(set(repos))
|
||||
|
||||
|
||||
def search_commits(term, repos=None):
|
||||
"""Every commit whose message mentions `term`, in any branch, with NO count window."""
|
||||
hits = []
|
||||
for r in (repos if repos is not None else owned_repos()):
|
||||
out = sh(["git", "-C", str(r), "log", "--all", "--format=%h\t%ad\t%s",
|
||||
"--date=short", "-i", f"--grep={term}"])
|
||||
for line in out.splitlines():
|
||||
parts = line.split("\t", 2)
|
||||
if len(parts) == 3:
|
||||
hits.append((r.name, parts[0], parts[1], parts[2]))
|
||||
return hits
|
||||
|
||||
|
||||
def register_mentions(term):
|
||||
"""Items in the authorization record mentioning `term`. The other half of the asymmetry."""
|
||||
n = 0
|
||||
pat = re.compile(re.escape(term), re.I)
|
||||
for f in REGISTER:
|
||||
if f.exists():
|
||||
n += len(pat.findall(f.read_text(errors="replace")))
|
||||
return n
|
||||
|
||||
|
||||
def controls():
|
||||
"""Same-run positive controls. The jurist specified these: the instrument must return
|
||||
two commits already known to exist, or it measured nothing and its zero means nothing."""
|
||||
ok, notes = True, []
|
||||
hits = search_commits("LFS")
|
||||
shas = {h[1] for h in hits}
|
||||
for known, why in (("0677e8a", "chamber-library — LFS retired, 17 commits rewritten"),
|
||||
("95760ff", "dotfiles — global git-lfs hooks removed")):
|
||||
if not any(s.startswith(known[:7]) for s in shas):
|
||||
ok = False
|
||||
notes.append(f"CONTROL FAIL: {known} not returned ({why})")
|
||||
# negative control: a term that cannot plausibly be in any commit message
|
||||
if search_commits("zzqqxx-not-a-real-term-9971"):
|
||||
ok = False
|
||||
notes.append("CONTROL FAIL: a nonsense term returned hits")
|
||||
return ok, notes, len(hits)
|
||||
|
||||
|
||||
def report(term):
|
||||
ok, notes, _ = controls()
|
||||
if not ok:
|
||||
print("⚠ INSTRUMENT NOT VERIFIED — the result below is unestablished.")
|
||||
for n in notes:
|
||||
print(" " + n)
|
||||
print()
|
||||
hits = search_commits(term)
|
||||
reg = register_mentions(term)
|
||||
print(f"PRIOR ART: {term!r}")
|
||||
print(f" commits mentioning it : {len(hits)} (all branches, no count window)")
|
||||
print(f" register mentions : {reg} (PENDING, PENDING-archive, REVIEWED)")
|
||||
print()
|
||||
for repo, sha, date, subj in sorted(hits, key=lambda h: h[2]):
|
||||
print(f" {date} {repo:34} {sha} {subj[:70]}")
|
||||
print()
|
||||
if hits and reg == 0:
|
||||
print(" ⚠ FINDING — PENDING-164's condition exactly: this mechanism has a history in")
|
||||
print(" the repos and NO trace in the authorization record. Whatever was decided")
|
||||
print(" about it was decided in a commit message. Read those commits before")
|
||||
print(" proposing anything about it.")
|
||||
elif hits:
|
||||
print(" Both surfaces carry it. Read the register items AND the commits — a ruling")
|
||||
print(" can post-date the commit that motivated it, or precede the one that undid it.")
|
||||
else:
|
||||
print(" No prior art found. ⚠ Absence here is weak evidence: it means no COMMIT")
|
||||
print(" MESSAGE names this term, not that nothing was decided about it.")
|
||||
return 0 if ok else 2
|
||||
|
||||
|
||||
def census():
|
||||
ok, notes, nlfs = controls()
|
||||
print("BACKWARD CENSUS — PENDING-164 AMENDMENT 1")
|
||||
print(f" instrument verified: {'YES' if ok else 'NO'}"
|
||||
+ ("" if ok else " ⚠ RESULT UNESTABLISHED"))
|
||||
for n in notes:
|
||||
print(" " + n)
|
||||
repos = owned_repos()
|
||||
print(f" owned repos (computed from remotes): {len(repos)}")
|
||||
print(f" positive control: 'LFS' returns {nlfs} commits incl. 0677e8a and 95760ff")
|
||||
print()
|
||||
seen, rows = set(), []
|
||||
for verb in CENSUS_VERBS:
|
||||
for repo, sha, date, subj in search_commits(verb, repos):
|
||||
if sha in seen:
|
||||
continue
|
||||
seen.add(sha)
|
||||
rows.append((date, repo, sha, subj))
|
||||
print(f" candidate adoption/retirement commits: {len(rows)}")
|
||||
print(" (a candidate is a commit whose SUBJECT reads like a mechanism decision;")
|
||||
print(" classification is the reader's, not this instrument's)")
|
||||
print()
|
||||
for date, repo, sha, subj in sorted(rows, reverse=True):
|
||||
print(f" {date} {repo:34} {sha} {subj[:74]}")
|
||||
return 0 if ok else 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "--census":
|
||||
sys.exit(census())
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "--selftest":
|
||||
ok, notes, n = controls()
|
||||
print(f"controls: {'PASS' if ok else 'FAIL'} ('LFS' → {n} commits)")
|
||||
for x in notes:
|
||||
print(" " + x)
|
||||
sys.exit(0 if ok else 1)
|
||||
if len(sys.argv) < 2:
|
||||
print("usage: prior-art.py <mechanism-name> | --census | --selftest")
|
||||
sys.exit(64)
|
||||
sys.exit(report(" ".join(sys.argv[1:])))
|
||||
Reference in New Issue
Block a user