quill: draft sprint protocol

This commit is contained in:
quill committed 2026-10-28 05:56:06 +00:00
1 parent ea525f92a0
commit f3d812ffe8
28 files changed
+2233 -569

No files matched your search

+121 -8
View File
@@ -109,7 +109,7 @@ USAGE
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, 73 cells
python3 tools/queue_index.py --selftest # fixture corpus, 80 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.
@@ -186,6 +186,25 @@ def record_form(line, qid):
return None
def record_detail(line, qid):
"""The first word after a record's bold lead -- `DONE`, `CLOSED`, `opened`.
The heading loop's `role_detail` already names the first word after a
continuation heading's dash; this is the same field for a continuation
record, so the table says *why* a second block exists without a reader
having to open it.
"""
body = BULLET.sub("", line.strip())
if not body.startswith("**"):
return ""
inner = body[2:].lstrip("*").lstrip()
if inner.startswith(qid):
inner = inner[len(qid):]
for word in inner.lstrip("—-–: ").split():
return word.strip("*().,;:").strip("*")
return ""
def split_lines(text):
"""Lines without their terminators, plus the byte length each line occupies."""
lines = text.split("\n")
@@ -293,10 +312,44 @@ def parse(text):
for qid in sorted(mentioned, key=lambda s: int(s[1:]))
if qid not in heading_ids and mentioned[qid]["record"] is not None]
# tier two, later records (Q103, 2026-10-28): an id's SECOND block-initial
# record -- a closure, a correction -- is an item too, with its own bounds.
# Before this, only the first record line per id cut anything, so every later
# closure block was charged to whichever item preceded it: measured on this
# queue before the fix, `**Q103 -- DONE ...**` (30 lines appended at the foot)
# grew Q104's row from 5,990 to 14,007 bytes, and Q100's own DONE block at
# :12915 sat inside Q101's row. That is the same swallow the id class had,
# one level down.
#
# The admission rule is deliberately narrow, because `record_form` alone is
# too loose here: 171 lines in this queue carry a record form for some id and
# 49 ids have more than one, but most of the extras are bullet status lines
# (`- **Q16:** unchanged at ...`) that are prose inside an item and must not
# split it. A later record is a boundary only when it BEGINS a block: the
# line opens with `**` at column 0, and the line above it is blank or a `---`
# rule or an HTML comment. Measured: 52 lines qualify, every one of them a
# standalone block in the file.
def begins_block(i):
prev = lines[i - 2].strip() if i >= 2 else ""
return prev == "" or prev == "---" or prev.startswith("<!--")
first_records = {(r[0], r[1]) for r in records}
later = []
for i, ln in enumerate(lines, 1):
if i in fenced or not ln.startswith("**") or not begins_block(i):
continue
for qid in sorted(set(ID_TOKEN.findall(ln)), key=lambda s: int(s[1:])):
if (i, qid) in first_records or record_form(ln, qid) != "BOLD-LEAD":
continue
later.append((i, qid, "BOLD-LEAD"))
break
# Every item opens somewhere and owns the lines up to the next opening: a
# heading, or a record that opens an id with no heading. Nothing else cuts a
# heading, or a record that opens an id with no heading, or a later
# block-initial record for an id that is already an item. Nothing else cuts a
# section, so a bold *mention* inside a section does not split it.
boundaries = sorted({h[0] for h in headings} | {r[0] for r in records})
boundaries = sorted({h[0] for h in headings} | {r[0] for r in records}
| {r[0] for r in later})
def end_of(line_no):
nxt = [b for b in boundaries if b > line_no]
@@ -315,9 +368,18 @@ def parse(text):
"role_detail": detail, "title": clip(rest.lstrip("—- ").strip(), 200)})
for line_no, qid, form in records:
raw = lines[line_no - 1]
seen.setdefault(qid, line_no)
items.append({"id": qid, "line": line_no, "kind": "record", "role": "record",
"role_detail": form,
"title": clip(BULLET.sub("", raw).strip(), 200)})
for line_no, qid, form in later:
raw = lines[line_no - 1]
role = "continuation" if qid in seen else "record"
seen.setdefault(qid, line_no)
items.append({"id": qid, "line": line_no, "kind": "record", "role": role,
"role_detail": record_detail(raw, qid) if role == "continuation"
else form,
"title": clip(BULLET.sub("", raw).strip(), 200)})
items.sort(key=lambda it: it["line"])
for it in items:
@@ -349,6 +411,12 @@ def parse(text):
# reported because a reader needs the line and the shape.
nested = []
for it in blocks:
# one row per id, not per block: a later closure block for the same id is
# an item with bounds (see `items`), but the table below is the id's
# record -- its form and how often the file names it -- so the opening
# block stands for it (Q103, 2026-10-28).
if it["role"] != "record":
continue
qid = it["id"]
rec = mentioned[qid]
idx = [k for k, cand in enumerate(items) if cand["line"] == it["line"]][0]
@@ -490,17 +558,23 @@ def build_doc(payload):
lines.append("**What this is.** One row per item of `WORK-QUEUE.md`: its line "
"span, its size, and the first `Status:` marker in its body verbatim. "
"An item is a `## ` section, or a record that opens an id with no heading "
"of its own (`kind` says which, and such an id's block runs to the line "
"of its own, or a later block-initial record for an id that is already an "
"item (`kind` and `role` say which, and each item's block runs to the line "
"before the next item opens). Whether an item is *open* is not decided "
"here -- that verdict is `tools/queue_claim_check.py`'s, and this document "
"does not overrule it.")
lines.append("")
blocks = payload.get("blocks", [])
open_blocks = [b for b in blocks if b["role"] == "record"]
later_blocks = [b for b in blocks if b["role"] != "record"]
lines.append("**What it exposes.** The queue is two-tier. %d sections carry %d ids because "
"%d ids own a second, continuation section; %d further ids are opened by a "
"record and own no heading at all, and they have rows and extents here.%s"
"record and own no heading at all, and they have rows and extents here -- "
"%d record blocks in all, %d of them a later closure or correction for an id "
"already opened.%s"
% (len(payload["sections"]), len(payload["ids_with_section"]),
len(payload["ids_multi_section"]), len(payload.get("blocks", [])),
nested_prose(payload["nested"])))
len(payload["ids_multi_section"]), len(open_blocks), len(blocks),
len(later_blocks), nested_prose(payload["nested"])))
lines.append("")
lines.append("| # | id | kind | lines | bytes | role | title | first `Status:` |")
lines.append("|---|---|---|---|---|---|---|---|")
@@ -824,6 +898,45 @@ def selftest():
check("items still tile across a block boundary",
[(i["id"], i["line"], i["end_line"]) for i in gap["items"]],
[("Q99", 1, 4), ("Q102", 5, 8), ("Q100", 9, 9)])
# --- a second record block for the same id is an item too (Q103) --------
# A closure block used to be charged to whichever item preceded it: measured
# on the real queue, appending `**Q103 -- DONE ...**` grew Q104's row from
# 5,990 to 14,007 bytes. These cells pin the rule and its two refusals.
sec = parse("## Q99 — a\n\nbody\n\n"
"**Q102 — OPEN (pipe).**\n\nthe opening block\n\n---\n\n"
"**Q102 — DONE at `abc1234`.**\n\nthe closure block\n")
check("a second block-initial record is its own item",
[(i["id"], i["line"], i["role"], i["role_detail"]) for i in sec["items"]],
[("Q99", 1, "opening", ""), ("Q102", 5, "record", "BOLD-LEAD"),
("Q102", 11, "continuation", "DONE")])
check("the opening block stops before the closure block",
[(b["id"], b["line"], b["end_line"]) for b in sec["blocks"]],
[("Q102", 5, 10), ("Q102", 11, 13)])
# slice, not [-1]: under a mutation that cuts no block this must read as a
# failed cell, not as a traceback out of the selftest (measured: it did).
check("the closure block owns the tail",
[(b["line"], b["end_line"]) for b in sec["blocks"]][-1:], [(11, 13)])
check("the nested table keeps one row for the id, not one per block",
[(r["id"], r["line"]) for r in sec["nested"]], [("Q102", 5)])
# Refusal 1: a bullet-led record inside a section is prose in a list, not a
# boundary. `- **Q102 -- DONE**` must not split the section that holds it --
# and here Q102 owns a heading, so the bullet is not its first record either.
bullet = parse("## Q99 — a\n\nbody\n\n## Q102 — d\n\nprose\n\n"
"- **Q102 — DONE at `abc1234`.**\n\nmore body\n")
check("a bullet-led record does not cut the section",
[(i["id"], i["line"], i["end_line"]) for i in bullet["items"]],
[("Q99", 1, 4), ("Q102", 5, 11)])
check("...and it adds no block row",
[(r["id"], r["form"]) for r in bullet["nested"]], [])
# Refusal 2: column 0 is not enough either -- the line must begin a block,
# i.e. the line above is blank, a `---` rule or an HTML comment.
glued = parse("## Q99 — a\n\nbody\n\n## Q102 — d\n\nprose runs on\n"
"**Q102 — DONE.**\n\ntail\n")
check("a column-0 record glued to prose does not cut the section",
[(i["id"], i["line"], i["end_line"]) for i in glued["items"]],
[("Q99", 1, 4), ("Q102", 5, 10)])
check("bytes are the file's own length", p["queue_bytes"], len(FIXTURE.encode()))
check("sha256 is the file's own", p["queue_sha256"],
hashlib.sha256(FIXTURE.encode()).hexdigest())
@@ -1027,7 +1140,7 @@ def main(argv=None):
ap.add_argument("--check", metavar="PATH", help="re-derive and compare a rendered index")
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, 73 cells")
ap.add_argument("--selftest", action="store_true", help="fixture corpus, 80 cells")
args = ap.parse_args(argv)
if args.selftest:
return selftest()