forge: re-verify iter_citations DRY refactor behavior-preserving (8/8, fresh census)

This commit is contained in:
forge committed 2026-10-21 10:09:43 +00:00
1 parent 54b1e1322b
commit d499796c35
1 file changed
+89
@@ -0,0 +1,89 @@
# iter_citations DRY Refactor — Fresh Re-verification
Tool: `tools/citation_resolve_check.py` (forge lane: Refactor — DRY consolidation).
## State
- Original (HEAD `58069c0`): blob `efa77a2`, 488 lines, **no** `iter_citations`.
- Refactored (working tree): 500 lines, `iter_citations()` + `Cite` shared by `scan()` and `_expect()`.
- Source change is **intentionally left unstaged** (see scope note): the verifier derives the
"original" via `git show HEAD:tools/citation_resolve_check.py`, so HEAD must stay pre-refactor
while the working tree holds the refactored build. Landing the source is a separate,
deliberate downstream step (the established forge pattern, cf. `86d5b27`/`4c89084`).
This re-verification was run at `2026-10-21T10:07:36Z` against current repo HEAD `58069c0`.
The repo has grown since the original Oct-21-07:25 landing run (EXPLICIT 524->525, mentions
8570->8703), so the comparison is recomputed against the live tip rather than replayed.
## The smell (unchanged)
The blocks()/fence_mask()/PAT/mention/explicit/bare/classify loop was inlined TWICE:
`scan()` (production census, tallies fenced/mention stats + rows) and `_expect()` (selftest
fixture grader, silently drops the fenced/mention stats). Two walkers, two rule sets for
"is this a mention / is this quoted" -- a classification change in one would not be mirrored
in the other, so the self-test could pass on its 14 fixtures while the census diverged. Latent
fault.
## The refactor (unchanged)
One `iter_citations(text, here, store)` generator yielding `Cite` namedtuples, consumed by
both callers. `Cite` carries the full classification
(`abs_line`, `in_fence`, `kind`, `target`, `want`, `verdict`, `have`,
`named_has`, `self_has`, `end`, `ctx`); each consumer decides what to DO with a row, not how
to walk the text. Equivalence holds: same `fence_mask()`/per-file, same `blocks()` scope, same
`PAT` ordering, same `last` threading, same `abs_line`; `here` threads as `p` in `scan()` and
as the `here` arg in `_expect()`; the `mention` predicate
`m.group("path") and m.group("line") is None` is exactly `c.kind == "mention"`, so the
fenced/mention buckets collapse identically.
## Evidence (measured -- re-run against current HEAD)
Verifier: `wizard-work/forge/verify_citation_resolve_check_dry_refactor.py`
(original materialized from `git show HEAD:tools/citation_resolve_check.py`, refactored read
from the working tree). This run's verbatim output (`iter_citations_fresh_verify.txt`):
```
[ok ] selftest: original 14/14 rc 0
[ok ] selftest: refactored 14/14 rc 0
[ok ] selftest: identical stdout (byte-for-byte)
[ok ] live scan: original ran rc 0
[ok ] live scan: refactored ran rc 0
[ok ] live scan: identical findings (citations)
[ok ] live scan: identical stats
[ok ] live scan: identical default stdout (rc 0, byte-identical)
verify: 8 checks, 8 passed, 0 failed
```
Exit code 0.
Self-test on the refactored (working-tree) tool:
```
self-test: 14 fixtures, 14 passed, 0 failed
```
Exit code 0.
Live census -- both versions against the SAME current HEAD `58069c0`:
- EXPLICIT `<path>:<line>` CITE claims: 525 -- RESOLVES 166 / STALE_LINE 0 / EXTERNAL_PATH 359
- BARE `:<line>` CANDIDATES: 1877 -- AS_NAMED 150 / AS_SELF 794 / AMBIGUOUS 57 / EXTERNAL_NAMED 268 / UNRESOLVED 608
- file mentions with no line: 8703 (occurrences) -- seeds inheritance scope
- fenced skipped: 6 citations, 517 mentions -- quoted material, not asserted
- distinct explicitly cited targets: 146
- stale: 0 citations (default `--only stale` run returns empty, rc 0)
- findings (`citations[]`) and `stats{}` are **byte-identical** between HEAD-original and
working-tree-refactored.
## Verdict
PASS -- the `iter_citations()` DRY consolidation in `tools/citation_resolve_check.py` is
behavior-preserving against current repo state: 14/14 self-test fixtures, identical findings
(2,402 rows: 525 explicit + 1,877 bare) and identical stats across the live census, and
byte-identical default stdout, between the HEAD original and the working-tree refactored build
(8/8 checks, exit 0). The mention/fenced predicate is unified without altering any result.
## CHECK (rerun the verifier)
```
python3 /root/troupe-standup/wizard-work/forge/verify_citation_resolve_check_dry_refactor.py
```
Exits 0 on full pass (8/8), 1 otherwise. The command's own exit code is the verdict; no
tautological suffix is appended.