doc_census_check (volt): a number ending a line and its unit opening the next is ONE claim -- joined only when structural, spent only when a leg prints that unit, every unbound pair named; 16-module-docstring A/B 134->140 (+6, -0), 4-tool census +1 MATCHES and 0 verdicts moved, selftest 82->104 cells
This commit is contained in:
1 parent
3487b2b4ea
commit
495a591e08
4 files changed
+375
-19
No files matched your search
@@ -10264,3 +10264,17 @@ Artifact: `/root/.hermes/wizard-outputs/volt/2026-10-18-index-stale/` (`REPORT.m
|
|||||||
- **Nothing else moves.** No item opened or closed; open set unchanged (`Q37:5278` pipe, career-lane `Q53:7303` held for Alexander). The RED/GREEN proof stands as written: mutant `733acc5` rc 1 naming `--baseline`/`--repo` and `gone_tool.py`, its parent rc 0.
|
- **Nothing else moves.** No item opened or closed; open set unchanged (`Q37:5278` pipe, career-lane `Q53:7303` held for Alexander). The RED/GREEN proof stands as written: mutant `733acc5` rc 1 naming `--baseline`/`--repo` and `gone_tool.py`, its parent rc 0.
|
||||||
|
|
||||||
— Volt
|
— Volt
|
||||||
|
|
||||||
|
**Volt tick 2026-10-20 14:3xZ — the census reader learns the archive's own line break: a number that ends a line and a unit that opens the next is one claim, and it is spent only when a leg prints that unit.** (Clock read immediately before this edit — 14:34Z; ledger's last line at `3487b2b` was `— Volt`; guard run and index re-rendered in this same commit.)
|
||||||
|
|
||||||
|
- **The defect, at the line, on the archive.** `tools/queue_claim_check.py:90`'s pinned pair `1,229,541 B / 9,953 lines` was broken across two lines at `70fa8b2`, and `doc_census_check.py`'s claim reader was line-local — a number only counts when its unit is ADJACENT. Measured, not asserted: the reader blob at `3487b2b` over `--rev 70fa8b2 --tools tools/queue_claim_check.py` reads **16 claims checked**; the reader landed here reads **17** on the same revision (`wrapped: 2 pair(s) read across a line break, 1 spent, 1 not a claim`). No verdict moved on either side — the claim simply stopped existing, with every command exiting 0.
|
||||||
|
- **The control on the other side.** `4e6b2ef` put the pair back on one line; **both** readers read **17 claims** there, and this reader reports **1 pair** (the prose `62 notes`), 0 spent. So the six-candidate count below is a measurement of the archive's prose, not a number the join invents to justify itself.
|
||||||
|
- **The reading rule is structural, and the spending rule is a leg.** `WRAP_LEAD`/`WRAP_UNIT` refuse what the adjacency reader already refused: a number welded to a preceding `-`, `/`, `.`, `:`, `_` or alphanumeric is not standalone, and a hyphen behind the unit makes it a compound adjective — `2026-10-18`, `UTF-8`, `0/1` and `9 / other-party` are four selftest refusal cells. Whether a joined pair is a *claim* is decided where this tool already decides it: **some leg must print that unit under its own spelling** (`wrap_bound`). There is no English word list, and the plural fold that `keys_for` applies to a one-line claim is deliberately refused here: measured at HEAD, the fold spent `the queue's own reply 62 / notes it` against a printed key `note` lifted out of a PASS line's prose and would have graded a correct sentence **STALE 62-vs-7**. That pair is now `WRAP_UNBOUND` — printed, counted in the banner, never dropped.
|
||||||
|
- **The reading change is confined, and this is the measurement that says so.** A/B of the old and new `claims_in` over all **16** tracked `tools/*.py` MODULE docstrings at the landed revision: **134 claims -> 140, added 6, removed 0**, and the six are exactly the candidates — `69 filenames` (`checkin_check.py:14`), `1,062 CONTENT_SHA256` (`citation_hash_class.py:53`), `18 cells` (`doc_census_check.py:81`), `0 without` (`:165`), `24 spendable` (`:209`), `62 notes` (`queue_claim_check.py:119`). Full census over the four tools that carry a candidate, at HEAD: **32 verdict rows -> 33, exactly +1 `MATCHES`** (`1,062 CONTENT_SHA256`), **0 removed, 0 verdicts moved**.
|
||||||
|
- **The instruments, at the tree that carries the change.** `--selftest` **104 cells, 104 passed, 0 failed** (was 82: 22 new cells; the six end-to-end cells are three stub tools differing only in whether a leg binds the unit — rc 0 / rc 1 / rc 0 — plus the fold pair and its one-line boundary). `doc_command_check.py --repo . --fail` **46 command(s) over 14 oracle(s) -- OK 46**, rc 0. `selftest_sweep.py` **16 tools, 16 OK, 0 fatal** — the NO_PROBE trap this lane hit on its previous tool does not fire, because this change adds no tool. `ruff check --select F,E9 tools/` clean.
|
||||||
|
- **One figure in my own artifact did not reproduce, and it is corrected by append.** `2026-10-20-wrap-land/REPORT.md` (14:19Z) states the reader A/B as "**150 claims identical, 0 removed, 6 added**". Re-measured this tick: **134 -> 140**. The delta (6, the same six) reproduces; the base does not, so the base was wrong and the claim is restated as measured. `REPORT.md` now carries the correction, and the two files it named but never wrote — `check.sh` and `files.sha256` — exist as of this tick.
|
||||||
|
- **The gate, and the fault in it that is not mine.** At `3487b2b` (the commit this append follows, with the tool change in the worktree): `verify.py --repo .` **5 legs, 4 pass, 1 fault, 0 ungradable, rc 1**. The fault is `checkin`: `2026-10-19-zephyrus.md` (`DUPLICATE`) and `2026-10-19-zephyrus-sovereignty.md` (`BAD_NAME,DUPLICATE`). A tree that carries none of this change reads the same two faults (2 new, 35 known, rc 1), so the leg was red before this tick and is left for the check-in ledger's owner rather than absorbed into a baseline by this lane.
|
||||||
|
- **What this does not do.** It does not read function or class docstrings — the scope is `docstring_span`'s MODULE docstring, and two real wrapped counts live outside it (`29 literal` in `append_only_audit.py`, `74 files` in `checkin_check.py`), named in the code comment and left unread rather than widened quietly. It does not decide English; a leg's print decides. It does not change a one-line claim's verdict, `--save-vocab`, or the digest rules. And it cannot spend a wrap whose unit the tool prints under a *different* label — by construction that stays `WRAP_UNBOUND`.
|
||||||
|
- **Nothing operational.** No queue item opened or closed; open set unchanged (`Q37:5278` pipe, career-lane `Q53:7303` held for Alexander). Tracked files changed: `tools/doc_census_check.py`, this append, the index re-render, and this lane's own day's check-in (third pass). No another-party file edited, no secret printed, no issue/PR/release/deploy surface. Artifact: `/root/.hermes/wizard-outputs/volt/2026-10-20-wrap-land/` (`REPORT.md` + correction, `check.sh`, `files.sha256`, `before/`, `after/`).
|
||||||
|
|
||||||
|
— Volt
|
||||||
@@ -84,3 +84,54 @@ rather than by growing those numbers.
|
|||||||
**Correction, same tick (06:4xZ) — the "deliberately not done" paragraph above is wrong, and the fix is landed.** `selftest_sweep.py` discovers every tracked tool and grades the ABSENCE of a probe as fatal, so leaving its probe axes alone was never a neutral choice: at `ba2bb3b` the tool row read `OK 15 cells / 15 cells / 15 cells` while `read-refusal: 21 probes, 20 ok, 1 fault (NO_PROBE)`, `malformed-input: 19 probes, 18 ok, 1 fault (NO_PROBE)`, sweep **rc 1**. Two rows were added — `("doc_command_check.py", ["--repo", "{nope}"])` and `("doc_command_check.py", "not-a-repo", ["--repo", "{notrepo}"], 2, "cannot read repo")` — and the axes read **21/21** and **19/19**, sweep **16 tools, 16 OK, 0 fatal, rc 0**.
|
**Correction, same tick (06:4xZ) — the "deliberately not done" paragraph above is wrong, and the fix is landed.** `selftest_sweep.py` discovers every tracked tool and grades the ABSENCE of a probe as fatal, so leaving its probe axes alone was never a neutral choice: at `ba2bb3b` the tool row read `OK 15 cells / 15 cells / 15 cells` while `read-refusal: 21 probes, 20 ok, 1 fault (NO_PROBE)`, `malformed-input: 19 probes, 18 ok, 1 fault (NO_PROBE)`, sweep **rc 1**. Two rows were added — `("doc_command_check.py", ["--repo", "{nope}"])` and `("doc_command_check.py", "not-a-repo", ["--repo", "{notrepo}"], 2, "cannot read repo")` — and the axes read **21/21** and **19/19**, sweep **16 tools, 16 OK, 0 fatal, rc 0**.
|
||||||
|
|
||||||
A second count in that file was already wrong before this tick and is corrected here: the malformed-axis comment said `Eleven tools must refuse at rc 2`; parsed from `MALFORMED_PROBES` itself, the list held **12** such tools at `ba2bb3b` (18 rows: 13 refused at 2 before this row, 4 graded at 0/1) and holds **13** after (`probe_axes.py`, 19 rows: rc 2 → 13 tools, rc 0 → 3, rc 1 → 1). The comment now reads `Thirteen`. Also named: the tick block's `43 commands over 13 oracles` was the untracked reading — with this tool in the tree its own three documented commands join the scan, **46 over 14, all OK**.
|
A second count in that file was already wrong before this tick and is corrected here: the malformed-axis comment said `Eleven tools must refuse at rc 2`; parsed from `MALFORMED_PROBES` itself, the list held **12** such tools at `ba2bb3b` (18 rows: 13 refused at 2 before this row, 4 graded at 0/1) and holds **13** after (`probe_axes.py`, 19 rows: rc 2 → 13 tools, rc 0 → 3, rc 1 → 1). The comment now reads `Thirteen`. Also named: the tick block's `43 commands over 13 oracles` was the untracked reading — with this tool in the tree its own three documented commands join the scan, **46 over 14, all OK**.
|
||||||
|
|
||||||
|
## Third pass — 14:3xZ
|
||||||
|
|
||||||
|
Landed the change the 04:03Z tick could only hand up: `doc_census_check.py`'s
|
||||||
|
claim reader now joins a number that ends a line to a unit that opens the next,
|
||||||
|
so the archive's own 79-column wrap can no longer retire a claim silently.
|
||||||
|
|
||||||
|
The RED is on the archive, not a fixture: at `70fa8b2` the reader blob at HEAD
|
||||||
|
reads **16 claims** for `queue_claim_check.py` and this reader reads **17**, with
|
||||||
|
no verdict moving on either side — the pinned pair `1,229,541 B / 9,953 lines`
|
||||||
|
had simply stopped being a claim. `4e6b2ef`, the repair, reads **17 on both**
|
||||||
|
readers, which is the control that the six-candidate count is the archive's prose
|
||||||
|
and not a number the join invents.
|
||||||
|
|
||||||
|
The design choice worth recording is where "is this a claim?" is answered. Not
|
||||||
|
in a word list: a wrapped pair is spent only when some leg prints its unit under
|
||||||
|
that exact spelling. The plural fold a one-line claim gets is refused here, and
|
||||||
|
that refusal is measured — with the fold, `reply 62 / notes it` binds a printed
|
||||||
|
key `note` lifted from a PASS line's prose and a correct sentence grades
|
||||||
|
**STALE 62-vs-7**. It is now `WRAP_UNBOUND`: printed, counted, not graded.
|
||||||
|
|
||||||
|
Confinement: A/B of old vs new `claims_in` over all 16 tracked module docstrings
|
||||||
|
reads **134 -> 140, +6, -0**, the six named; the full census over the four tools
|
||||||
|
carrying a candidate moves **32 verdict rows to 33**, exactly the one that should
|
||||||
|
move (`1,062 CONTENT_SHA256`, `MATCHES`). Selftest **104/104** (was 82);
|
||||||
|
`doc_command_check` 46/14 OK; sweep 16 tools 16 OK 0 fatal; ruff clean.
|
||||||
|
|
||||||
|
One figure in my own 14:19Z artifact did not reproduce on re-measurement — it
|
||||||
|
said "150 claims identical" where the measurement is 134 -> 140. The delta was
|
||||||
|
right and the base was wrong; the report now carries the correction rather than
|
||||||
|
a quiet edit, and the `check.sh` and `files.sha256` it named but never wrote
|
||||||
|
exist as of this tick.
|
||||||
|
|
||||||
|
## Blocked
|
||||||
|
|
||||||
|
`verify.py`'s `checkin` leg is red at `3487b2b` and was red before this change:
|
||||||
|
`2026-10-19-zephyrus.md` (`DUPLICATE`) and `2026-10-19-zephyrus-sovereignty.md`
|
||||||
|
(`BAD_NAME,DUPLICATE`), 2 new against a 35-file baseline, reproduced in a tree
|
||||||
|
carrying none of this work. Not absorbed into the baseline by this lane.
|
||||||
|
|
||||||
|
## Next
|
||||||
|
|
||||||
|
Function and class docstrings are still unread (`29 literal` in
|
||||||
|
`append_only_audit.py`, `74 files` in `checkin_check.py`). Widening
|
||||||
|
`docstring_span` would spend both, which makes it a change with its own A/B, not
|
||||||
|
a rider on this one.
|
||||||
|
|
||||||
|
## Ask
|
||||||
|
|
||||||
|
No ask. No item opened or closed (open set unchanged: `Q37:5278` pipe,
|
||||||
|
career-lane `Q53:7303` held for Alexander).
|
||||||
+9
-9
@@ -56,7 +56,7 @@
|
|||||||
| 46 | Q44 | 6162-6705 | 88496 | opening | The pin class: redirect every constant composed from the live data root, not only `SNAPSHOT_PATH` *(Helm lane; opened 2026-10-12 by the pipe, per Q43's own closing sentence — "extend the redirect … | DONE 2026-10-12 — `recoveries/helm-root-redirect.md` (Merlin, Helm lane); the closure block is at the foot |
|
| 46 | Q44 | 6162-6705 | 88496 | opening | The pin class: redirect every constant composed from the live data root, not only `SNAPSHOT_PATH` *(Helm lane; opened 2026-10-12 by the pipe, per Q43's own closing sentence — "extend the redirect … | DONE 2026-10-12 — `recoveries/helm-root-redirect.md` (Merlin, Helm lane); the closure block is at the foot |
|
||||||
| 47 | Q48 | 6706-6825 | 15123 | opening | The runtime-resolution redirect: close the class Q45's literals cannot see | DONE 2026-10-13 — `recoveries/helm-runtime-redirect.md` (Merlin, Helm lane), scratch tree |
|
| 47 | Q48 | 6706-6825 | 15123 | opening | The runtime-resolution redirect: close the class Q45's literals cannot see | DONE 2026-10-13 — `recoveries/helm-runtime-redirect.md` (Merlin, Helm lane), scratch tree |
|
||||||
| 48 | Q49 | 6826-7593 | 92050 | opening | The runtime-resolved root's live write path: name it, reproduce it, then close it | open and unclaimed. Opened by the pipe 2026-10-13 |
|
| 48 | Q49 | 6826-7593 | 92050 | opening | The runtime-resolved root's live write path: name it, reproduce it, then close it | open and unclaimed. Opened by the pipe 2026-10-13 |
|
||||||
| 49 | Q45 | 7594-10266 | 450070 | opening | §9 follow-on — the home-directory channel *(Helm lane; Merlin)* | -- |
|
| 49 | Q45 | 7594-10280 | 455748 | opening | §9 follow-on — the home-directory channel *(Helm lane; Merlin)* | -- |
|
||||||
|
|
||||||
## Ids with no `## ` heading
|
## Ids with no `## ` heading
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ Opened as records inside another section. `line` is the record's own opening lin
|
|||||||
| Q50 | 6990 | 6990 | 46 | Q49 | BULLET+BOLD | BOLD-LEAD |
|
| Q50 | 6990 | 6990 | 46 | Q49 | BULLET+BOLD | BOLD-LEAD |
|
||||||
| Q51 | 7106 | 7106 | 37 | Q49 | BULLET+BOLD | BOLD-LEAD |
|
| Q51 | 7106 | 7106 | 37 | Q49 | BULLET+BOLD | BOLD-LEAD |
|
||||||
| Q52 | 7167 | 7167 | 90 | Q49 | BULLET+BOLD | BOLD-LEAD |
|
| Q52 | 7167 | 7167 | 90 | Q49 | BULLET+BOLD | BOLD-LEAD |
|
||||||
| Q53 | 7292 | 7246 | 137 | Q49 | BULLET+BOLD | BOLD-LEAD |
|
| Q53 | 7292 | 7246 | 138 | Q49 | BULLET+BOLD | BOLD-LEAD |
|
||||||
| Q63 | 9918 | 9909 | 17 | Q45 | BULLET+BOLD | BOLD-LEAD |
|
| Q63 | 9918 | 9909 | 17 | Q45 | BULLET+BOLD | BOLD-LEAD |
|
||||||
|
|
||||||
**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`.
|
**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`.
|
||||||
@@ -217,7 +217,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
|||||||
"form": "BOLD-LEAD",
|
"form": "BOLD-LEAD",
|
||||||
"id": "Q53",
|
"id": "Q53",
|
||||||
"line": 7292,
|
"line": 7292,
|
||||||
"refs": 137,
|
"refs": 138,
|
||||||
"section": "Q49",
|
"section": "Q49",
|
||||||
"shape": "BULLET+BOLD"
|
"shape": "BULLET+BOLD"
|
||||||
},
|
},
|
||||||
@@ -236,9 +236,9 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
|||||||
"end_line": 8,
|
"end_line": 8,
|
||||||
"line": 1
|
"line": 1
|
||||||
},
|
},
|
||||||
"queue_bytes": 1342331,
|
"queue_bytes": 1348009,
|
||||||
"queue_lines": 10266,
|
"queue_lines": 10280,
|
||||||
"queue_sha256": "c73fd68aff2531ffcc4d63dd31b082aff531455ba1f5ede7d42a4f1b99b66c19",
|
"queue_sha256": "cd51315f3a4ee29ccbbf915dad2c79771c5ed49ecbe145fa431777ebe253c5e0",
|
||||||
"sections": [
|
"sections": [
|
||||||
{
|
{
|
||||||
"bytes": 3139,
|
"bytes": 3139,
|
||||||
@@ -817,11 +817,11 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
|||||||
"title": "The runtime-resolved root's live write path: name it, reproduce it, then close it"
|
"title": "The runtime-resolved root's live write path: name it, reproduce it, then close it"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"bytes": 450070,
|
"bytes": 455748,
|
||||||
"end_line": 10266,
|
"end_line": 10280,
|
||||||
"id": "Q45",
|
"id": "Q45",
|
||||||
"line": 7594,
|
"line": 7594,
|
||||||
"lines": 2673,
|
"lines": 2687,
|
||||||
"role": "opening",
|
"role": "opening",
|
||||||
"role_detail": "",
|
"role_detail": "",
|
||||||
"status": null,
|
"status": null,
|
||||||
|
|||||||
+301
-10
@@ -48,6 +48,33 @@ WHAT IT MEASURES (read-only: this tool only writes --json)
|
|||||||
A claim is `<digits> <unitword>` with the unit word ADJACENT, which is the
|
A claim is `<digits> <unitword>` with the unit word ADJACENT, which is the
|
||||||
archive's own notation. A bare number is not a claim and is not checked.
|
archive's own notation. A bare number is not a claim and is not checked.
|
||||||
|
|
||||||
|
A WRAPPED PAIR IS A CLAIM ONLY WHEN A LEG CAN BIND IT. A number that ENDS one
|
||||||
|
line with its unit opening the next is the same claim the archive writes on
|
||||||
|
one line, and until 2026-10-20 this reader was line-local: a docstring reflow
|
||||||
|
retired the claim silently while every command exited 0 (measured -- the
|
||||||
|
pinned pair in `queue_claim_check.py` fell out of the census and the claim
|
||||||
|
count fell with it, with no verdict moving). The reader now joins the pair,
|
||||||
|
under the same refusals the adjacency reader already applies: a number welded
|
||||||
|
to a preceding `-`, `/`, `.`, `:`, `_` or letter is not standalone, so a
|
||||||
|
date's tail and `UTF-8` and `0/1` are not counts, and a unit with a hyphen
|
||||||
|
behind it is a compound adjective. Whether the joined pair is SPENT is a
|
||||||
|
second question, and it is answered by the census rather than by a lexicon of
|
||||||
|
English: the pair is graded only when some leg prints its unit UNDER THAT
|
||||||
|
SPELLING, and every pair no leg binds is printed as WRAP_UNBOUND and counted
|
||||||
|
in the banner, never dropped. The spelling is exact and that is deliberate: a
|
||||||
|
plural fold (`notes` -> `note`) is affordable for a one-line claim, because
|
||||||
|
both sides are census voice, but a wrap is this reader's hypothesis about two
|
||||||
|
lines of prose. Measured at HEAD 2026-10-20, the fold spent `the queue's own
|
||||||
|
reply 62 / notes it` and graded a correct sentence STALE 62-vs-7; with the
|
||||||
|
fold refused, that pair is WRAP_UNBOUND and the one wrapped claim a leg really
|
||||||
|
binds -- `1,062 CONTENT_SHA256` at `citation_hash_class.py:53` -- is the only
|
||||||
|
one graded. The other five candidates are named, not graded: `69 filenames`
|
||||||
|
(`checkin_check.py:14`), `18 cells`, `24 spendable` and `0 without` (all
|
||||||
|
three in this file -- its `--selftest`, fast-mode and `--fail` paragraphs),
|
||||||
|
and `62 notes` (`queue_claim_check.py:119`). With `--no-run` there is no leg, so
|
||||||
|
no wrap is spent and each one is reported unbound -- a mode that cannot see a
|
||||||
|
census cannot bind a claim.
|
||||||
|
|
||||||
TWO ORACLE LEGS, AND WHY THE SECOND ONE EXISTS
|
TWO ORACLE LEGS, AND WHY THE SECOND ONE EXISTS
|
||||||
Leg 1 is the tool's own run at the block's revision, exactly as above. Leg 2
|
Leg 1 is the tool's own run at the block's revision, exactly as above. Leg 2
|
||||||
is the SAME TOOL'S `--selftest`, added 2026-10-16 after the control plane
|
is the SAME TOOL'S `--selftest`, added 2026-10-16 after the control plane
|
||||||
@@ -220,7 +247,7 @@ FAILING ON THE CLASS IT CATCHES (`--fail`)
|
|||||||
USAGE
|
USAGE
|
||||||
python3 doc_census_check.py [--repo DIR] [--rev HEAD] [--tools NAME...]
|
python3 doc_census_check.py [--repo DIR] [--rev HEAD] [--tools NAME...]
|
||||||
[--json OUT] [--fail] [--no-run] [--vocab PATH] [--save-vocab PATH]
|
[--json OUT] [--fail] [--no-run] [--vocab PATH] [--save-vocab PATH]
|
||||||
[--selftest] # selftest: 82 cells, one per claim class
|
[--selftest] # selftest: 104 cells, one per claim class
|
||||||
"""
|
"""
|
||||||
import argparse
|
import argparse
|
||||||
import ast
|
import ast
|
||||||
@@ -290,6 +317,51 @@ CLAIM = re.compile(
|
|||||||
r"(?P<unit>[A-Za-z_][A-Za-z0-9_]*|[A-Z][A-Z_]{2,})\b(?!-)")
|
r"(?P<unit>[A-Za-z_][A-Za-z0-9_]*|[A-Z][A-Z_]{2,})\b(?!-)")
|
||||||
CLAIM_EQ = re.compile(
|
CLAIM_EQ = re.compile(
|
||||||
r"(?P<unit>[A-Za-z_][A-Za-z0-9_]*)\s*[:=]\s*\**\s*(?P<num>[0-9]+(?:,[0-9]{3})*)")
|
r"(?P<unit>[A-Za-z_][A-Za-z0-9_]*)\s*[:=]\s*\**\s*(?P<num>[0-9]+(?:,[0-9]{3})*)")
|
||||||
|
|
||||||
|
# A WRAPPED PAIR: the number ENDS one line and its unit OPENS the next. Until
|
||||||
|
# 2026-10-20 this reader was line-local, so a claim that a docstring's 79-column
|
||||||
|
# wrap cut in two was not a claim at all. That is not cosmetic: `queue_claim_check
|
||||||
|
# .py`'s pinned pair `1,229,541 B / 9,953 lines` was broken onto two lines at
|
||||||
|
# `70fa8b2` and the census silently fell from seventeen claims to sixteen with no
|
||||||
|
# verdict moving -- the archive's own instrument, blind to the archive's own
|
||||||
|
# notation, while every command exited 0. Measured at HEAD 2026-10-20 by running
|
||||||
|
# this reader over all sixteen tracked `tools/*.py` MODULE docstrings -- the only
|
||||||
|
# scope docstring_span reads: SIX
|
||||||
|
# number-ends-a-line candidates -- FOUR real counts with their unit
|
||||||
|
# (`69 filenames` at checkin_check.py:14, `1,062 CONTENT_SHA256` at
|
||||||
|
# citation_hash_class.py:53, `18 cells` and `24 spendable` in this file's
|
||||||
|
# `--selftest` and fast-mode paragraphs) and TWO words that merely open a
|
||||||
|
# sentence (`0 without` in the `--fail` paragraph here, `62 notes` at
|
||||||
|
# queue_claim_check.py:119). The same reader at `70fa8b2`, where the break was
|
||||||
|
# introduced, reads seven -- the same six plus the pinned `9,953 lines` pair --
|
||||||
|
# and spends it, so that docstring reads sixteen claims against the old reader
|
||||||
|
# and seventeen against this one. `4e6b2ef`, the commit that put the pair back on
|
||||||
|
# one line, is the control on the other side: it reads six candidates and
|
||||||
|
# seventeen claims on BOTH readers, so the six is a measurement of HEAD's prose
|
||||||
|
# and not a fallback the join quietly invents. A twelve-row artifact was produced
|
||||||
|
# that day by a looser net that counted every number ending a line with any word
|
||||||
|
# after it, non-counts included; the reader itself reads six.
|
||||||
|
# The same measurement over FUNCTION and CLASS docstrings -- which this tool does
|
||||||
|
# not read at all, module docstrings only -- finds two more real counts, `29
|
||||||
|
# literal` in append_only_audit.py and `74 files` in checkin_check.py. They are
|
||||||
|
# named here rather than quietly excluded: a scope the reader cannot see is
|
||||||
|
# worth knowing, and the join would spend either one if the scope ever widened.
|
||||||
|
#
|
||||||
|
# WHY THERE IS NO WORD LIST HERE. The obvious reader is "join the wrap unless the
|
||||||
|
# unit is a verb", and it needs an English lexicon that would refuse a real claim
|
||||||
|
# the day one is written in an unlucky voice. The discrimination is made where
|
||||||
|
# this tool already makes it: A WRAPPED PAIR IS SPENT ONLY WHEN A LEG PRINTS ITS
|
||||||
|
# UNIT (see check_tool). At HEAD that spends exactly one of the six --
|
||||||
|
# `1,062 CONTENT_SHA256`, whose census prints the label -- and the other five
|
||||||
|
# (`69 filenames`, `18 cells`, `24 spendable`, `0 without`, `62 notes`) are
|
||||||
|
# printed unbound and never graded. The structural half below is the part that
|
||||||
|
# must not be guessed at, and it is the same half the adjacency reader already
|
||||||
|
# enforces: a number welded to a preceding `-`, `/`, `.`, `:`, `_` or
|
||||||
|
# alphanumeric is not standalone (`2026-10-18`, `UTF-8` and `0/1` are three of
|
||||||
|
# the strings this refuses, each one a refusal cell in the selftest below), and
|
||||||
|
# a unit with a hyphen behind it is a compound adjective, not a unit noun.
|
||||||
|
WRAP_LEAD = re.compile(r"(?:^|[\s(\[{*`'\"])(?P<num>[0-9]+(?:,[0-9]{3})*)[ \t]*$")
|
||||||
|
WRAP_UNIT = re.compile(r"^[ \t]*(?P<unit>[A-Za-z_][A-Za-z0-9_]*|[A-Z][A-Z_]{2,})\b(?!-)")
|
||||||
REV_LONG = re.compile(r"\b[0-9a-f]{7,40}\b")
|
REV_LONG = re.compile(r"\b[0-9a-f]{7,40}\b")
|
||||||
|
|
||||||
# A hex run introduced as a DIGEST is not a revision, and reading it as one costs
|
# A hex run introduced as a DIGEST is not a revision, and reading it as one costs
|
||||||
@@ -477,15 +549,20 @@ def ordinal_at(raw, pos):
|
|||||||
|
|
||||||
|
|
||||||
def claims_in(blk):
|
def claims_in(blk):
|
||||||
"""[(line, value, unit, token, offset)] for one block.
|
"""[(line, value, unit, token, offset, wrapped)] for one block.
|
||||||
|
|
||||||
Both claim forms are read and a claim found by both is reported once. The
|
Both claim forms are read and a claim found by both is reported once. The
|
||||||
offset is measured on the block text so a RESTATEMENT (far apart) can be
|
offset is measured on the block text so a RESTATEMENT (far apart) can be
|
||||||
told from an ENUMERATION of neighbouring sub-counts, the same
|
told from an ENUMERATION of neighbouring sub-counts, the same
|
||||||
discrimination num_agreement_check.py applies.
|
discrimination num_agreement_check.py applies.
|
||||||
|
|
||||||
|
`wrapped` is True for a claim whose number ends one line and whose unit opens
|
||||||
|
the next -- see WRAP_LEAD. It is a reading decision only: whether such a pair
|
||||||
|
is SPENT is decided in check_tool, by whether a leg prints its unit.
|
||||||
"""
|
"""
|
||||||
out, off = [], 0
|
out, off, starts = [], 0, []
|
||||||
for ln, raw in blk:
|
for ln, raw in blk:
|
||||||
|
starts.append(off)
|
||||||
found = {}
|
found = {}
|
||||||
for m in CLAIM.finditer(raw):
|
for m in CLAIM.finditer(raw):
|
||||||
u = m.group("unit")
|
u = m.group("unit")
|
||||||
@@ -504,8 +581,25 @@ def claims_in(blk):
|
|||||||
found[m.start()] = (int(m.group("num").replace(",", "")), u, m.group(0))
|
found[m.start()] = (int(m.group("num").replace(",", "")), u, m.group(0))
|
||||||
for pos in sorted(found):
|
for pos in sorted(found):
|
||||||
val, u, tok = found[pos]
|
val, u, tok = found[pos]
|
||||||
out.append((ln, val, u, tok, off + pos))
|
out.append((ln, val, u, tok, off + pos, False))
|
||||||
off += len(raw) + 1
|
off += len(raw) + 1
|
||||||
|
for i in range(len(blk) - 1):
|
||||||
|
ln, raw = blk[i]
|
||||||
|
m = WRAP_LEAD.search(raw)
|
||||||
|
if not m:
|
||||||
|
continue
|
||||||
|
um = WRAP_UNIT.match(blk[i + 1][1])
|
||||||
|
if not um:
|
||||||
|
continue
|
||||||
|
u = um.group("unit")
|
||||||
|
if len(u) < 3 or u.lower() in STOPWORDS or re.fullmatch(r"[qQ]\d+", u):
|
||||||
|
continue
|
||||||
|
if ordinal_at(raw, m.start("num")):
|
||||||
|
continue
|
||||||
|
num = m.group("num")
|
||||||
|
out.append((ln, int(num.replace(",", "")), u, f"{num} {u}",
|
||||||
|
starts[i] + m.start("num"), True))
|
||||||
|
out.sort(key=lambda r: r[4])
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
@@ -633,7 +727,7 @@ def _fixture_checks():
|
|||||||
for first, blk in blocks(lines, 1, len(lines)):
|
for first, blk in blocks(lines, 1, len(lines)):
|
||||||
revs = block_revs("\n".join(r for _, r in blk))
|
revs = block_revs("\n".join(r for _, r in blk))
|
||||||
revs_seen |= set(revs)
|
revs_seen |= set(revs)
|
||||||
for ln, val, unit, _tok, _pos in claims_in(blk):
|
for ln, val, unit, _tok, _pos, _w in claims_in(blk):
|
||||||
got.append((unit, val))
|
got.append((unit, val))
|
||||||
if first == 1:
|
if first == 1:
|
||||||
first_block.append((unit, val))
|
first_block.append((unit, val))
|
||||||
@@ -646,7 +740,7 @@ def _fixture_checks():
|
|||||||
# the tightened separator, one cell per form it now refuses, plus the
|
# the tightened separator, one cell per form it now refuses, plus the
|
||||||
# positive control -- a rule that refuses everything proves nothing
|
# positive control -- a rule that refuses everything proves nothing
|
||||||
def claims_of(text):
|
def claims_of(text):
|
||||||
return [(u, v) for _ln, v, u, _t, _p in claims_in([(1, text)])]
|
return [(u, v) for _ln, v, u, _t, _p, _w in claims_in([(1, text)])]
|
||||||
|
|
||||||
check("claims: a welded digit-and-letter run is not a claim",
|
check("claims: a welded digit-and-letter run is not a claim",
|
||||||
claims_of("sha 83acffe0 / rev 9188dd3 at HEAD"), [])
|
claims_of("sha 83acffe0 / rev 9188dd3 at HEAD"), [])
|
||||||
@@ -675,6 +769,57 @@ def _fixture_checks():
|
|||||||
check("claims: a count beside a line cite is still a claim",
|
check("claims: a count beside a line cite is still a claim",
|
||||||
claims_of("open set: Q37:5278 while 13 rows close"), [("rows", 13)])
|
claims_of("open set: Q37:5278 while 13 rows close"), [("rows", 13)])
|
||||||
check("claims: the block's rev is read", "babdadc" in revs_seen, True)
|
check("claims: the block's rev is read", "babdadc" in revs_seen, True)
|
||||||
|
|
||||||
|
# THE WRAPPED PAIR, 2026-10-20. A count that ends one line with its unit
|
||||||
|
# opening the next is the same claim the archive writes on one line, and
|
||||||
|
# every ADMIT text below is a real wrap copied out of the docstring it was
|
||||||
|
# measured in -- not an invented example. The four ADMIT cells are the four
|
||||||
|
# counts at HEAD; the fifth candidate, `62 notes`, is a verb and is settled
|
||||||
|
# by binding (wrap_bound, the FOLD cells below) rather than by these cells.
|
||||||
|
# The four refusal cells are the structural half, synthesized rather than
|
||||||
|
# copied because at HEAD no welded or hyphenated string survives to the
|
||||||
|
# candidate stage for a text to be lifted from.
|
||||||
|
def claims_lines(text):
|
||||||
|
blk = [(i + 1, raw) for i, raw in enumerate(text.split("\n"))]
|
||||||
|
return [(u, v, w) for _ln, v, u, _t, _p, w in claims_in(blk)]
|
||||||
|
|
||||||
|
check("wrap: a number ending a line and its unit opening the next is a claim",
|
||||||
|
claims_lines("Twenty-five of the 69\nfilenames are not the form"),
|
||||||
|
[("filenames", 69, True)])
|
||||||
|
check("wrap: a thousands separator survives the join",
|
||||||
|
claims_lines("594 BLOB_OID / 1,062\nCONTENT_SHA256 and the rest"),
|
||||||
|
[("BLOB_OID", 594, False), ("CONTENT_SHA256", 1062, True)])
|
||||||
|
check("wrap: a backtick before the number and a closing one after the unit",
|
||||||
|
claims_lines("a selftest that prints `18\ncells` -- the defect class"),
|
||||||
|
[("cells", 18, True)])
|
||||||
|
check("wrap: an adjective is a unit when it is the count's own word",
|
||||||
|
claims_lines("observed keys at 30c8120, 24\nspendable, the other 398"),
|
||||||
|
[("spendable", 24, True)])
|
||||||
|
check("wrap: a claim that does not wrap is not tagged",
|
||||||
|
claims_lines("a selftest that prints 18 cells"), [("cells", 18, False)])
|
||||||
|
check("wrap: the same text wrapped and unwrapped is two claims, not three",
|
||||||
|
claims_lines("prints 18 cells\nand 18\ncells"),
|
||||||
|
[("cells", 18, False), ("cells", 18, True)])
|
||||||
|
# the four refusals, one cell each -- the structural half no candidate at
|
||||||
|
# HEAD exercises, because the reader refuses these strings before the join
|
||||||
|
check("wrap: a date's tail is welded to its hyphens, not a count",
|
||||||
|
claims_lines("--today 2026-10-18\npython3 tools/x.py"), [])
|
||||||
|
check("wrap: `UTF-8` ends a line and is still not a count",
|
||||||
|
claims_lines("a malformed name, non-UTF-8\nbytes are refused"), [])
|
||||||
|
check("wrap: a slash-separated pair (`0/1`) is not a count",
|
||||||
|
claims_lines("exit 0/1\npython3 tools/x.py"), [])
|
||||||
|
check("wrap: a hyphen behind the joined unit is a compound adjective",
|
||||||
|
claims_lines("the queue read 65 same-party / 9\nother-party. Neither"),
|
||||||
|
[])
|
||||||
|
# THE FOLD, as a unit rule: keys_for folds a plural (it must -- a one-line
|
||||||
|
# claim and a printed label are both census voice), wrap_bound does not.
|
||||||
|
check("wrap: a plural verb is bound by no fold -- `notes` is not `note`",
|
||||||
|
wrap_bound("notes", [({"note": {7}}, set(), "")]), False)
|
||||||
|
check("wrap: and a unit printed under its own spelling IS bound",
|
||||||
|
wrap_bound("notes", [({"notes": {62}}, set(), "")]), True)
|
||||||
|
check("wrap: an uppercase label binds to the lowercase printed key",
|
||||||
|
wrap_bound("CONTENT_SHA256",
|
||||||
|
[({"content_sha256": {1062}}, set(), "")]), True)
|
||||||
# the digest rule, one signal per cell, and the negative control between
|
# the digest rule, one signal per cell, and the negative control between
|
||||||
# them -- the text of each is the text of the defect, measured at HEAD
|
# them -- the text of each is the text of the defect, measured at HEAD
|
||||||
check("revs: `sha256 <hex>` is a digest, not the block's revision",
|
check("revs: `sha256 <hex>` is a digest, not the block's revision",
|
||||||
@@ -906,6 +1051,40 @@ def _fixture_checks():
|
|||||||
"\n471 UNRESOLVED at the head.\n" + "pad " * 80 + "\n"
|
"\n471 UNRESOLVED at the head.\n" + "pad " * 80 + "\n"
|
||||||
'441 UNRESOLVED at the tail.\n"""\n'
|
'441 UNRESOLVED at the tail.\n"""\n'
|
||||||
"print('UNRESOLVED: 471')\n")
|
"print('UNRESOLVED: 471')\n")
|
||||||
|
# THE WRAPPED PAIR, three stubs that differ only in whether a leg can
|
||||||
|
# bind the unit: agreeing, disagreeing, and a wrap that is prose.
|
||||||
|
with open(os.path.join(td, "tools", "stub_wrap_ok.py"), "w") as fh:
|
||||||
|
fh.write('"""A stub whose claim wraps onto the next line.\n'
|
||||||
|
"\nWe measured 7\n"
|
||||||
|
'widgets at HEAD.\n"""\n'
|
||||||
|
"print('widgets: 7')\n")
|
||||||
|
with open(os.path.join(td, "tools", "stub_wrap_stale.py"), "w") as fh:
|
||||||
|
fh.write('"""A stub whose wrapped claim disagrees with its census.\n'
|
||||||
|
"\nWe measured 9\n"
|
||||||
|
'widgets at HEAD.\n"""\n'
|
||||||
|
"print('widgets: 7')\n")
|
||||||
|
with open(os.path.join(td, "tools", "stub_wrap_unbound.py"), "w") as fh:
|
||||||
|
fh.write('"""A stub whose wrap is prose, not a census.\n'
|
||||||
|
"\nIt exited 0\n"
|
||||||
|
'without a census.\n"""\n'
|
||||||
|
"print('widgets: 7')\n")
|
||||||
|
# THE FOLD, end to end -- the false fault measured on the real archive at
|
||||||
|
# HEAD (queue_claim_check.py:119, `reply 62 / notes it`). `notes` folds to
|
||||||
|
# the printed key `note`, which the loose printed reader picked out of a
|
||||||
|
# PASS line's prose, so a plural fold would spend this sentence and grade
|
||||||
|
# it STALE. The pair must land as unbound instead.
|
||||||
|
with open(os.path.join(td, "tools", "stub_wrap_fold.py"), "w") as fh:
|
||||||
|
fh.write('"""A stub whose wrap is a verb that folds onto a key.\n'
|
||||||
|
"\nThe queue's own reply 62\n"
|
||||||
|
'notes it).\n"""\n'
|
||||||
|
"print('note: 7')\n")
|
||||||
|
# ...and the boundary: the SAME text on ONE line is still a claim, still
|
||||||
|
# folded, still graded -- the narrowing is the wrap's price, not a new
|
||||||
|
# rule for the adjacency reader.
|
||||||
|
with open(os.path.join(td, "tools", "stub_note_adjacent.py"), "w") as fh:
|
||||||
|
fh.write('"""A stub whose one-line claim folds onto a key.\n'
|
||||||
|
"\nThe queue's own reply 62 notes it).\n\"\"\"\n"
|
||||||
|
"print('note: 7')\n")
|
||||||
genv = dict(os.environ, GIT_AUTHOR_NAME="t", GIT_AUTHOR_EMAIL="t@t",
|
genv = dict(os.environ, GIT_AUTHOR_NAME="t", GIT_AUTHOR_EMAIL="t@t",
|
||||||
GIT_COMMITTER_NAME="t", GIT_COMMITTER_EMAIL="t@t")
|
GIT_COMMITTER_NAME="t", GIT_COMMITTER_EMAIL="t@t")
|
||||||
for sub in (["init", "-q"], ["add", "-A"], ["commit", "-qm", "fixture"]):
|
for sub in (["init", "-q"], ["add", "-A"], ["commit", "-qm", "fixture"]):
|
||||||
@@ -929,6 +1108,24 @@ def _fixture_checks():
|
|||||||
run_gate("--tools", "tools/stub_split.py", "--no-run", "--fail"), 0)
|
run_gate("--tools", "tools/stub_split.py", "--no-run", "--fail"), 0)
|
||||||
check("gate e2e: --fail with the run grades that same split (rc 1)",
|
check("gate e2e: --fail with the run grades that same split (rc 1)",
|
||||||
run_gate("--tools", "tools/stub_split.py", "--fail"), 1)
|
run_gate("--tools", "tools/stub_split.py", "--fail"), 1)
|
||||||
|
# THE WRAPPED PAIR, END TO END. Three stubs whose only difference is
|
||||||
|
# whether a leg prints the unit the wrap names, so these cells grade the
|
||||||
|
# SPENDING rule and not just the reading rule above.
|
||||||
|
check("gate e2e: a wrapped claim a leg binds, agreeing, is rc 0",
|
||||||
|
run_gate("--tools", "tools/stub_wrap_ok.py", "--fail"), 0)
|
||||||
|
check("gate e2e: and its wrapped VALUE is graded -- disagreeing is rc 1",
|
||||||
|
run_gate("--tools", "tools/stub_wrap_stale.py", "--fail"), 1)
|
||||||
|
check("gate e2e: a wrapped pair no leg binds is not a claim (rc 0)",
|
||||||
|
run_gate("--tools", "tools/stub_wrap_unbound.py", "--fail"), 0)
|
||||||
|
check("gate e2e: --no-run spends no wrap and fails on none (rc 0)",
|
||||||
|
run_gate("--tools", "tools/stub_wrap_stale.py", "--no-run",
|
||||||
|
"--fail"), 0)
|
||||||
|
# THE FOLD: a plural verb must not be bound to a singular printed key by
|
||||||
|
# a wrap, and the same text on one line must still be graded.
|
||||||
|
check("gate e2e: a wrapped verb is NOT bound by a plural fold (rc 0)",
|
||||||
|
run_gate("--tools", "tools/stub_wrap_fold.py", "--fail"), 0)
|
||||||
|
check("gate e2e: the same words on one line ARE folded and graded (rc 1)",
|
||||||
|
run_gate("--tools", "tools/stub_note_adjacent.py", "--fail"), 1)
|
||||||
# the process exit code through the vocabulary, both directions, plus
|
# the process exit code through the vocabulary, both directions, plus
|
||||||
# the two ways a vocabulary can fail to be usable at all
|
# the two ways a vocabulary can fail to be usable at all
|
||||||
vpath = os.path.join(td, "vocab-names-unit.json")
|
vpath = os.path.join(td, "vocab-names-unit.json")
|
||||||
@@ -1017,6 +1214,30 @@ def _fixture_checks():
|
|||||||
if l.strip().startswith("ADVISORY above (no census label")],
|
if l.strip().startswith("ADVISORY above (no census label")],
|
||||||
["ADVISORY above (no census label and no cached vocabulary): "
|
["ADVISORY above (no census label and no cached vocabulary): "
|
||||||
"5@3, 7@5 -- reported, not graded"])
|
"5@3, 7@5 -- reported, not graded"])
|
||||||
|
# A WRAP IS NEVER SILENT: the banner says how many pairs were read
|
||||||
|
# across a break and how many were spent, on both outcomes.
|
||||||
|
_rc, out_wb = run_gate_out("--tools", "tools/stub_wrap_ok.py")
|
||||||
|
check("gate e2e: the banner says the wrap was read and spent",
|
||||||
|
[l.strip() for l in out_wb.splitlines()
|
||||||
|
if l.strip().startswith("wrapped:")],
|
||||||
|
["wrapped: 1 pair(s) read across a line break, 1 spent, "
|
||||||
|
"0 not a claim (no leg prints the unit)"])
|
||||||
|
_rc, out_wu = run_gate_out("--tools", "tools/stub_wrap_unbound.py")
|
||||||
|
check("gate e2e: an unbound wrap is counted and named, not dropped",
|
||||||
|
[l.strip() for l in out_wu.splitlines()
|
||||||
|
if l.strip().startswith(("wrapped:", "WRAP_UNBOUND"))],
|
||||||
|
["wrapped: 1 pair(s) read across a line break, 0 spent, "
|
||||||
|
"1 not a claim (no leg prints the unit)",
|
||||||
|
"WRAP_UNBOUND tools/stub_wrap_unbound.py:3 0 without -- the "
|
||||||
|
"unit is printed by no leg"])
|
||||||
|
_rc, out_wf = run_gate_out("--tools", "tools/stub_wrap_fold.py")
|
||||||
|
check("gate e2e: a folded verb is named UNBOUND, not graded STALE",
|
||||||
|
[l.strip() for l in out_wf.splitlines()
|
||||||
|
if l.strip().startswith(("wrapped:", "WRAP_UNBOUND", "STALE"))],
|
||||||
|
["wrapped: 1 pair(s) read across a line break, 0 spent, "
|
||||||
|
"1 not a claim (no leg prints the unit)",
|
||||||
|
"WRAP_UNBOUND tools/stub_wrap_fold.py:3 62 notes -- the unit "
|
||||||
|
"is printed by no leg"])
|
||||||
|
|
||||||
print(f"selftest: {cells[0]} cells, {cells[0] - bad[0]} passed, {bad[0]} failed")
|
print(f"selftest: {cells[0]} cells, {cells[0] - bad[0]} passed, {bad[0]} failed")
|
||||||
return 0 if ok else 1
|
return 0 if ok else 1
|
||||||
@@ -1118,6 +1339,29 @@ def unit_scope(unit, legs, no_run):
|
|||||||
return "NOT_A_CENSUS_UNIT"
|
return "NOT_A_CENSUS_UNIT"
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_bound(unit, legs):
|
||||||
|
"""True when some leg prints this unit under its OWN spelling.
|
||||||
|
|
||||||
|
This is keys_for WITHOUT the plural fold, and the narrowing is the whole
|
||||||
|
point. `keys_for` tries `unit.lower().rstrip("s")` because a one-line claim
|
||||||
|
and a printed label are both hand-written census voice (`18 claims` vs
|
||||||
|
`claim: 18`), so folding the plural costs nothing there. A WRAP IS NOT
|
||||||
|
HAND-WRITTEN CENSUS VOICE -- it is two lines this reader hypothesised into
|
||||||
|
one claim, and the word that opens the second line is a word in a sentence
|
||||||
|
far more often than it is a label: `the queue's own reply 62 / notes it`
|
||||||
|
folds `notes` onto a printed key `note`, and the tool printed that key only
|
||||||
|
because `parse_printed`'s loose reader took it out of the prose of its own
|
||||||
|
PASS line (`PASS v2 loose key: a Q7 continuation note is not an opening
|
||||||
|
record`). Measured 2026-10-20: that fold spent the pair and graded the
|
||||||
|
docstring STALE 62-vs-7 -- a false fault about a correct sentence.
|
||||||
|
So a wrap binds on the unit's own spelling or not at all; a pair that only a
|
||||||
|
fold would bind is printed as WRAP_UNBOUND and never graded, which is the
|
||||||
|
same landing place as a pair no leg touches.
|
||||||
|
"""
|
||||||
|
u = unit.lower()
|
||||||
|
return any(u in (printed or {}) for printed, _clone, _tag in legs)
|
||||||
|
|
||||||
|
|
||||||
def vocab_has(unit, vocab):
|
def vocab_has(unit, vocab):
|
||||||
"""True when a cached census vocabulary names this unit word.
|
"""True when a cached census vocabulary names this unit word.
|
||||||
|
|
||||||
@@ -1200,13 +1444,51 @@ def check_tool(repo, script, name, cache, run=True, tmpdir=".", isolation=240,
|
|||||||
out.append((selftest_leg[0][0], selftest_leg[0][1], "selftest"))
|
out.append((selftest_leg[0][0], selftest_leg[0][1], "selftest"))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
# A WRAPPED PAIR IS SPENT ONLY WHEN A LEG CAN BIND ITS UNIT. Joining a line
|
||||||
|
# break is a reading decision and it is the only place in this tool where a
|
||||||
|
# claim is manufactured out of two lines instead of found inside one, so it
|
||||||
|
# gets the tool's own test for census-hood rather than a lexicon of English:
|
||||||
|
# a unit some leg prints IS a unit; a word that merely opens a sentence is
|
||||||
|
# not, and the difference is measured on the tool's output rather than
|
||||||
|
# asserted in a word list. Measured at HEAD, spent: `1,062 CONTENT_SHA256`
|
||||||
|
# (citation_hash_class.py:53). Measured at HEAD, NOT spent and named in the
|
||||||
|
# banner: `69 filenames` (checkin_check.py:14, no leg prints `filenames`),
|
||||||
|
# `18 cells`, `24 spendable` and `0 without` (doc_census_check.py self), and
|
||||||
|
# `62 notes` (queue_claim_check.py:119, `reply 62 / notes it` -- prose, and
|
||||||
|
# only a plural fold would have bound it; see wrap_bound). Nothing is dropped
|
||||||
|
# silently -- every unbound pair is counted and printed (the `wrapped:` line
|
||||||
|
# in the banner), because a candidate that vanishes is the defect this rule
|
||||||
|
# exists to close. With no run there is no leg, so no wrap is spent and every
|
||||||
|
# one is reported unbound: a mode that cannot see a census cannot bind a
|
||||||
|
# claim, which is the same contract unit_scope already applies to a split.
|
||||||
|
wrap_candidates, wrap_unbound = 0, []
|
||||||
|
if any(w for _f, _r, cl, _b in blk_claims for _ln, _v, _u, _t, _p, w in cl):
|
||||||
|
kept_blocks = []
|
||||||
|
for first, revs, cl, btext in blk_claims:
|
||||||
|
rows = []
|
||||||
|
for ln, val, unit, tok, pos, wrapped in cl:
|
||||||
|
if not wrapped:
|
||||||
|
rows.append((ln, val, unit, tok, pos, wrapped))
|
||||||
|
continue
|
||||||
|
wrap_candidates += 1
|
||||||
|
bound = any(wrap_bound(unit, legs_for(first, r))
|
||||||
|
for r in (revs or ["HEAD"]))
|
||||||
|
if bound:
|
||||||
|
rows.append((ln, val, unit, tok, pos, wrapped))
|
||||||
|
else:
|
||||||
|
wrap_unbound.append({"file": name, "line": ln, "unit": unit,
|
||||||
|
"claim": val, "token": tok})
|
||||||
|
if rows:
|
||||||
|
kept_blocks.append((first, revs, rows, btext))
|
||||||
|
blk_claims = kept_blocks
|
||||||
|
|
||||||
# 1. INTERNAL SPLIT: one unit, one revision scope, two values, far enough
|
# 1. INTERNAL SPLIT: one unit, one revision scope, two values, far enough
|
||||||
# apart to be a restatement rather than a neighbouring sub-count.
|
# apart to be a restatement rather than a neighbouring sub-count.
|
||||||
splits, advisory, unchecked = [], [], collections.Counter()
|
splits, advisory, unchecked = [], [], collections.Counter()
|
||||||
by_unit = collections.defaultdict(list)
|
by_unit = collections.defaultdict(list)
|
||||||
for first, revs, cl, _b in blk_claims:
|
for first, revs, cl, _b in blk_claims:
|
||||||
scope = tuple(revs)
|
scope = tuple(revs)
|
||||||
for ln, val, unit, _t, pos in cl:
|
for ln, val, unit, _t, pos, _w in cl:
|
||||||
by_unit[(unit.upper() if unit.isupper() else unit.lower(), scope)].append(
|
by_unit[(unit.upper() if unit.isupper() else unit.lower(), scope)].append(
|
||||||
(first, ln, val, pos))
|
(first, ln, val, pos))
|
||||||
for (unit, scope), items in sorted(by_unit.items()):
|
for (unit, scope), items in sorted(by_unit.items()):
|
||||||
@@ -1261,7 +1543,7 @@ def check_tool(repo, script, name, cache, run=True, tmpdir=".", isolation=240,
|
|||||||
for first, revs, cl, _b in blk_claims:
|
for first, revs, cl, _b in blk_claims:
|
||||||
for rev in (revs or ["HEAD"]):
|
for rev in (revs or ["HEAD"]):
|
||||||
if is_self:
|
if is_self:
|
||||||
for ln, val, unit, tok, _pos in cl:
|
for ln, val, unit, tok, _pos, _w in cl:
|
||||||
verdicts.append({"file": name, "block": first, "line": ln,
|
verdicts.append({"file": name, "block": first, "line": ln,
|
||||||
"rev": rev, "unit": unit, "claim": val,
|
"rev": rev, "unit": unit, "claim": val,
|
||||||
"token": tok, "verdict": "SELF_NOT_RUN",
|
"token": tok, "verdict": "SELF_NOT_RUN",
|
||||||
@@ -1290,7 +1572,7 @@ def check_tool(repo, script, name, cache, run=True, tmpdir=".", isolation=240,
|
|||||||
legs = [l for l in legs if l[2] == "selftest"]
|
legs = [l for l in legs if l[2] == "selftest"]
|
||||||
if not legs:
|
if not legs:
|
||||||
continue
|
continue
|
||||||
for ln, val, unit, tok, _pos in cl:
|
for ln, val, unit, tok, _pos, _w in cl:
|
||||||
v, detail = adjudicate(legs, unit, val, revs)
|
v, detail = adjudicate(legs, unit, val, revs)
|
||||||
verdicts.append({"file": name, "block": first, "line": ln,
|
verdicts.append({"file": name, "block": first, "line": ln,
|
||||||
"rev": rev, "unit": unit, "claim": val,
|
"rev": rev, "unit": unit, "claim": val,
|
||||||
@@ -1299,8 +1581,9 @@ def check_tool(repo, script, name, cache, run=True, tmpdir=".", isolation=240,
|
|||||||
"unchecked": dict(unchecked),
|
"unchecked": dict(unchecked),
|
||||||
"claim_units": sorted({(u.upper() if u.isupper() else u.lower())
|
"claim_units": sorted({(u.upper() if u.isupper() else u.lower())
|
||||||
for _f, _r, cl, _b in blk_claims
|
for _f, _r, cl, _b in blk_claims
|
||||||
for _ln, _v, u, _t, _p in cl}),
|
for _ln, _v, u, _t, _p, _w in cl}),
|
||||||
"failures": failures, "verdicts": verdicts,
|
"failures": failures, "verdicts": verdicts,
|
||||||
|
"wrap_candidates": wrap_candidates, "wrap_unbound": wrap_unbound,
|
||||||
"self": is_self and run, "selftest_leg": (not run) or bool(selftest_leg and selftest_leg[0]),
|
"self": is_self and run, "selftest_leg": (not run) or bool(selftest_leg and selftest_leg[0]),
|
||||||
"blocks_with_claims": len(blk_claims)}
|
"blocks_with_claims": len(blk_claims)}
|
||||||
|
|
||||||
@@ -1461,6 +1744,14 @@ def main():
|
|||||||
f"{nstale} STALE claim(s), {nfail} leg failure(s), "
|
f"{nstale} STALE claim(s), {nfail} leg failure(s), "
|
||||||
f"{nclaims} claims checked"
|
f"{nclaims} claims checked"
|
||||||
+ (" [" + "; ".join(notes) + "]" if notes else ""))
|
+ (" [" + "; ".join(notes) + "]" if notes else ""))
|
||||||
|
if rep.get("wrap_candidates"):
|
||||||
|
print(f" wrapped: {rep['wrap_candidates']} pair(s) read across a "
|
||||||
|
f"line break, {rep['wrap_candidates'] - len(rep.get('wrap_unbound') or [])} "
|
||||||
|
f"spent, {len(rep.get('wrap_unbound') or [])} not a claim "
|
||||||
|
f"(no leg prints the unit)")
|
||||||
|
for u in rep.get("wrap_unbound") or []:
|
||||||
|
print(f" WRAP_UNBOUND {u['file']}:{u['line']} "
|
||||||
|
f"{u['token']} -- the unit is printed by no leg")
|
||||||
for s in rep["splits"]:
|
for s in rep["splits"]:
|
||||||
vals = ", ".join(f"{r['value']}@{r['line']}" for r in s["rows"])
|
vals = ", ".join(f"{r['value']}@{r['line']}" for r in s["rows"])
|
||||||
scope = ",".join(s["revs"]) or "no rev named"
|
scope = ",".join(s["revs"]) or "no rev named"
|
||||||
|
|||||||
Reference in new issue
Block a user