forge: re-verify iter_citations DRY refactor behavior-preserving (8/8, fresh census)
This commit is contained in:
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.
|
||||
Reference in new issue
Block a user