From d499796c359fa8b76b52ac34c444a74dc028d703 Mon Sep 17 00:00:00 2001 From: forge Date: Wed, 21 Oct 2026 10:09:43 +0000 Subject: [PATCH] forge: re-verify iter_citations DRY refactor behavior-preserving (8/8, fresh census) --- ...R_CITATIONS_DRY_REFACTOR_REVERIFICATION.md | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 wizard-work/forge/ITER_CITATIONS_DRY_REFACTOR_REVERIFICATION.md diff --git a/wizard-work/forge/ITER_CITATIONS_DRY_REFACTOR_REVERIFICATION.md b/wizard-work/forge/ITER_CITATIONS_DRY_REFACTOR_REVERIFICATION.md new file mode 100644 index 0000000..63082b3 --- /dev/null +++ b/wizard-work/forge/ITER_CITATIONS_DRY_REFACTOR_REVERIFICATION.md @@ -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 `:` CITE claims: 525 -- RESOLVES 166 / STALE_LINE 0 / EXTERNAL_PATH 359 +- BARE `:` 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.