diff --git a/docs/queue-index.md b/docs/queue-index.md index d2107c6..c8e9877 100644 --- a/docs/queue-index.md +++ b/docs/queue-index.md @@ -78,13 +78,7 @@ Opened as records inside another section. `section` is the heading whose body ho | Q58 | 8731 | 1 | Q45 | BULLET+BOLD | | Q62 | 9227 | 1 | Q45 | PLAIN | -## Ids referenced outside the queue entirely - -Id tokens in the 317 tracked `*.md` files under the prose corpus (`tools/` excluded: its fixtures carry synthetic ids by construction) that `WORK-QUEUE.md` never mentions. - -| id | files | -|---|---| -| Q63 | `recoveries/helm-pill-both-directions.md` | +**Not in this document.** Ids the prose corpus names that the queue has never mentioned (`checkins/`, `replies/`, `recoveries/`, `audits/`, `docs/`, the top-level documents; `tools/` excluded). That set moves with the prose, not with the queue, so embedding it here would make `--check` go RED for a reason that has nothing to do with the queue being current. It is reported on demand: `python3 tools/queue_index.py --outside`. ## The pinned parse diff --git a/tools/queue_index.py b/tools/queue_index.py index 5a4924c..d2618ee 100644 --- a/tools/queue_index.py +++ b/tools/queue_index.py @@ -37,6 +37,16 @@ WHAT IT MEASURES -- structural facts only, one row per `## ` section its fixtures carry synthetic ids by construction, and this tool's own selftest is one of them. + The `outside` leg is REPORTED, not embedded: `--outside` prints it, and the + rendered document does not contain it. It cannot. That set is a function of + the working tree's prose, not of the queue, so baking it into a document that + `--check` byte-compares against a fresh render means any checkin that quotes + an id turns the queue's gate RED for a reason that has nothing to do with the + queue. Measured on 2026-10-17: `--outside` read Q63 from `recoveries/`, then + Q63+Q77+Q99 once a checkin described the test that names Q77 -- same queue, + same sha256, three different documents. A table of contents must be a + function of the file it indexes. + Headings inside a fenced block are never sections; a heading whose id is followed by `closure --` or `§9 follow-on --` is still that id's section. @@ -50,7 +60,10 @@ WHAT IT DOES NOT DO whole-gate run found the table above the pin drifted while the pin still matched, because the document had begun listing itself in its own corpus. The rendered file is excluded from that corpus, which makes `--write` a fixed - point, and the bytes are now compared whole.) + point, and the bytes are now compared whole.) The document is therefore a + function of `WORK-QUEUE.md` alone: the same queue renders the same bytes + whatever the prose corpus says, which is what makes `--check` a statement + about the queue's currency and not about the last person to write a checkin. `--check` exit codes: 0 current, 1 stale (with the delta printed), 2 the document carries no parseable pinned block. @@ -59,10 +72,11 @@ WHAT IT DOES NOT DO USAGE python3 tools/queue_index.py --index # 49 sections, one screen each side + python3 tools/queue_index.py --outside # ids the prose corpus names and the queue does not python3 tools/queue_index.py --json out.json python3 tools/queue_index.py --write docs/queue-index.md python3 tools/queue_index.py --check docs/queue-index.md - python3 tools/queue_index.py --selftest # fixture corpus, 32 cells + python3 tools/queue_index.py --selftest # fixture corpus, 38 cells Re-run `--write` after any append to the queue. The document carries the queue's sha256, so a stale copy is a RED check, never a silent lie. @@ -280,7 +294,7 @@ def clip(text, limit): return cut.rstrip(" ,;:—-") + " …" -def build_doc(payload, outside, corpus_files): +def build_doc(payload): lines = [] lines.append("# The work queue's table of contents") lines.append("") @@ -324,22 +338,13 @@ def build_doc(payload, outside, corpus_files): lines.append("| %s | %d | %d | %s | %s |" % (r["id"], r["line"], r["refs"], r["section"] or "--", r["shape"])) lines.append("") - if outside is not None: - lines.append("## Ids referenced outside the queue entirely") - lines.append("") - lines.append("Id tokens in the %d tracked `*.md` files under the prose corpus " - "(`tools/` excluded: its fixtures carry synthetic ids by construction) " - "that `WORK-QUEUE.md` never mentions." % corpus_files) - lines.append("") - if outside: - lines.append("| id | files |") - lines.append("|---|---|") - for qid, files in outside.items(): - lines.append("| %s | %s |" % (qid, ", ".join("`%s`" % f for f in files[:4]) - + (" +%d" % (len(files) - 4) if len(files) > 4 else ""))) - else: - lines.append("None: every id the prose corpus cites is mentioned in the queue.") - lines.append("") + lines.append("**Not in this document.** Ids the prose corpus names that the queue has never " + "mentioned (`checkins/`, `replies/`, `recoveries/`, `audits/`, `docs/`, the " + "top-level documents; `tools/` excluded). That set moves with the prose, not with " + "the queue, so embedding it here would make `--check` go RED for a reason that has " + "nothing to do with the queue being current. It is reported on demand: " + "`python3 tools/queue_index.py --outside`.") + lines.append("") lines.append("## The pinned parse") lines.append("") lines.append("The block below is the parse this document renders, byte for byte. " @@ -411,8 +416,7 @@ def run(args): if pinned is None: print("UNVERIFIABLE: no parseable pinned block in %s" % args.check) return 2 - outside, corpus = outside_ids(repo, args.queue, exclude=(args.check,)) - render = build_doc(payload, outside, corpus or 0) + render = build_doc(payload) if render != doc: # The rendered prose is graded, not only the pin. A pin-only gate # stayed green while the table above it had drifted; that was the @@ -434,10 +438,18 @@ def run(args): print("index current: %s" % summary(payload)) return 0 - outside, corpus = outside_ids(repo, args.queue, exclude=(args.write,)) + outside, corpus = outside_ids(repo, args.queue, exclude=(args.write, args.check)) + if args.outside: + print("outside the queue: %d id(s) named by the %d tracked *.md files read " + "(`tools/` excluded), which `WORK-QUEUE.md` never mentions" % (len(outside or {}), corpus or 0)) + for qid, files in (outside or {}).items(): + print(" %-5s %s" % (qid, ", ".join(files[:4]) + + (" +%d" % (len(files) - 4) if len(files) > 4 else ""))) + return 0 + if args.write: with open(args.write, "w", encoding="utf-8") as fh: - fh.write(build_doc(payload, outside, corpus or 0)) + fh.write(build_doc(payload)) print("wrote %s (%d bytes)" % (args.write, os.path.getsize(args.write))) return 0 @@ -457,7 +469,7 @@ def run(args): for r in payload["nested"]: print("nested %-4s line %-5d refs %-3d inside %-4s %s" % (r["id"], r["line"], r["refs"], r["section"] or "--", r["shape"])) - if outside is not None and outside: + if outside: print("outside the queue: %s" % ", ".join(outside)) print() @@ -536,9 +548,9 @@ def selftest(): # --- the gate, round trip and both directions of falsification ---------- root = tempfile.mkdtemp(prefix="queue-index-selftest-") repo = os.path.join(root, "repo") - os.makedirs(repo) + os.makedirs(os.path.join(repo, "docs")) queue = os.path.join(repo, "WORK-QUEUE.md") - doc_path = os.path.join(repo, "index.md") + doc_path = os.path.join(repo, DOC_PATH) subprocess.check_call(["git", "-C", repo, "init", "-q", "-b", "main"]) subprocess.check_call(["git", "-C", repo, "config", "user.email", "s@invalid"]) subprocess.check_call(["git", "-C", repo, "config", "user.name", "s"]) @@ -552,7 +564,7 @@ def selftest(): buf = io.StringIO() with contextlib.redirect_stdout(buf): rc = run(argparse.Namespace(repo=repo, queue="WORK-QUEUE.md", index=False, - json=None, write=doc_path, check=None)) + json=None, write=doc_path, check=None, outside=False)) check("--write exits 0", rc, 0) check("document written", os.path.exists(doc_path), True) doc = open(doc_path, encoding="utf-8").read() @@ -561,17 +573,51 @@ def selftest(): buf = io.StringIO() with contextlib.redirect_stdout(buf): rc = run(argparse.Namespace(repo=repo, queue="WORK-QUEUE.md", index=False, - json=None, write=None, check=doc_path)) + json=None, write=None, check=doc_path, outside=False)) check("--check on its own output exits 0", rc, 0) check("--check says current", "index current:" in buf.getvalue(), True) + # --- the document is a function of the queue alone ----------------------- + # A prose file that names an id the queue never mentions must not move a + # byte of the document, and must not turn --check RED. Baking the corpus + # table into the document did both: same queue, three different documents, + # and a checkin quoting an id reddened a gate about the queue's currency. + with open(os.path.join(repo, "notes.md"), "w", encoding="utf-8") as fh: + fh.write("# notes\n\nQ63 is named only here; Q1 is a queue id.\n") + subprocess.check_call(["git", "-C", repo, "add", "notes.md"]) + before = open(doc_path, encoding="utf-8").read() + buf = io.StringIO() + with contextlib.redirect_stdout(buf): + rc = run(argparse.Namespace(repo=repo, queue="WORK-QUEUE.md", index=False, + json=None, write=doc_path, check=None, outside=False)) + check("re-render beside a prose mention exits 0", rc, 0) + check("a prose mention does not change the document", + open(doc_path, encoding="utf-8").read(), before) + buf = io.StringIO() + with contextlib.redirect_stdout(buf): + rc = run(argparse.Namespace(repo=repo, queue="WORK-QUEUE.md", index=False, + json=None, write=None, check=doc_path, outside=False)) + check("--check stays green when prose names an id", rc, 0) + + # --- the outside leg is reported, not embedded --------------------------- + buf = io.StringIO() + with contextlib.redirect_stdout(buf): + rc = run(argparse.Namespace(repo=repo, queue="WORK-QUEUE.md", index=False, + json=None, write=None, check=None, outside=True)) + out = buf.getvalue() + check("--outside exits 0", rc, 0) + check("--outside counts the corpus it actually read", + "1 id(s) named by the 2 tracked *.md files" in out, True) + check("--outside names Q63 and the file that carries it", + " Q63 notes.md" in out, True) + # falsify 1: an append moves the last section's extent with open(queue, "a", encoding="utf-8") as fh: fh.write("- an appended line.\n") buf = io.StringIO() with contextlib.redirect_stdout(buf): rc = run(argparse.Namespace(repo=repo, queue="WORK-QUEUE.md", index=False, - json=None, write=None, check=doc_path)) + json=None, write=None, check=doc_path, outside=False)) check("--check goes RED on an append", rc, 1) check("RED names the moved section", "changed extent or status" in buf.getvalue(), True) @@ -581,7 +627,7 @@ def selftest(): buf = io.StringIO() with contextlib.redirect_stdout(buf): rc = run(argparse.Namespace(repo=repo, queue="WORK-QUEUE.md", index=False, - json=None, write=None, check=doc_path)) + json=None, write=None, check=doc_path, outside=False)) check("--check goes RED on a new heading", rc, 1) check("RED names the new section", "new section(s): Q7" in buf.getvalue(), True) @@ -590,7 +636,7 @@ def selftest(): buf = io.StringIO() with contextlib.redirect_stdout(buf): rc = run(argparse.Namespace(repo=repo, queue="WORK-QUEUE.md", index=False, - json=None, write=None, check=doc_path)) + json=None, write=None, check=doc_path, outside=False)) check("no pin -> exit 2", rc, 2) check("no pin -> says so", "UNVERIFIABLE" in buf.getvalue(), True) @@ -608,7 +654,9 @@ def main(argv=None): ap.add_argument("--json", metavar="PATH", help="write the parse here") ap.add_argument("--write", metavar="PATH", help="render the index document here") ap.add_argument("--check", metavar="PATH", help="re-derive and compare a rendered index") - ap.add_argument("--selftest", action="store_true", help="fixture corpus, 32 cells") + ap.add_argument("--outside", action="store_true", + help="report ids the prose corpus names that the queue never mentions") + ap.add_argument("--selftest", action="store_true", help="fixture corpus, 38 cells") args = ap.parse_args(argv) if args.selftest: return selftest()