quill: draft sprint protocol
This commit is contained in:
1 parent
ea525f92a0
commit
f3d812ffe8
28 files changed
+2233
-569
No files matched your search
+121
-8
@@ -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()
|
||||
|
||||
Reference in new issue
Block a user