c21ca7b58e1bf95075c90bb4475bd0981c14302f
After chunk 4 verification on the Anti-Communist draft, ran v2
against the previously-untested ## Notes sections of HML (72 notes)
and Reading_Disrepair (25 notes) — 97 new notes for 204 total
across 3 drafts. The wider corpus surfaced 5 distinct issues that
weren't visible in the Anti-Communist data alone.
src/cmos/note_formatter.py:
1. Tighten substantive prose detector — exclude semicolon-bearing
inputs (chunk 5 task 1). The HML draft was dominated by compound
shortened references like:
See Author1, "Title;" Author2, "Title;" Author3, "Title."
17 of 72 HML notes matched this pattern, exceeded the 150-char
threshold, and had no citation skeleton markers, so they were
passed through verbatim by the chunk 3 detector. Compound
references use semicolons as item separators; substantive prose
doesn't. Adding `if ";" in stripped: return False` cleanly
separates the two without affecting the genuine substantive
notes (which contain none).
2. Rule 3 — distinguish comma-inside vs period-inside for
article/chapter title closing quote based on whether MORE
content follows the title. Surfaced by 8+ entries across drafts
producing the wrong `"Title,".` pattern (comma inside followed
by stray period outside) when the title is the last element of
the entry. Rule 3 now explicitly says: comma inside when more
content follows; period inside when title is the last element.
3. New rule 20 — preserve signal phrases verbatim. Surfaced by HML
[69] and [70] where "For example," was stripped while "See" was
preserved elsewhere. CMOS notes commonly open with signal
phrases (See, See also, For example, Cf., Compare, But see,
Contra, Accord, Quoted in) that indicate how a citation relates
to the surrounding argument. Stripping them is data loss.
4. Rule 1 — explicit "no comma between author name and 'et al.'"
in non-inverted note form. Surfaced by HML [69] where "Bignoli
et al." became "Bignoli, et al." (extra comma). The comma
before "et al." is a feature of inverted bibliography form,
not non-inverted note form. Rule 1 now includes WRONG examples.
5. Citation skeleton URL marker — also accept bare-domain URLs
without the https:// scheme. Surfaced by Reading_Disrepair [1]
GAO entry which had `files.gao.gov/...` without `https://`,
so the existing https?:// marker didn't match and the 190-char
citation was passed through as substantive prose. New pattern:
`\b\w{2,}(?:\.\w{2,})+/\S*` catches bare domains like
files.gao.gov/path without false-positiving on common things
like "e.g./" (single-char tokens excluded by {2,}).
Tests: 157/157 (was 153, +4 net new for prompt-content and regex
verification). The +4 is: compound-reference detection, genuine
substantive prose regression check, rule 3 / rule 20 / rule 1
prompt-content tests, bare-domain URL detection.
Path B: rule 18 (publishers, chunk 4) and rule 20 (signal phrases,
this commit) are v2-only. Rule 1 et al. clarification could in
principle apply to v1 too but v1 doesn't see "et al." in the same
non-inverted form. v1 untouched. 96/96 v1 tests still passing.
Real-draft validation pending — verification re-run against all
3 drafts will follow in the next step.
cmos — Chicago Manual of Style 18 bibliography reformatter
A Python tool that reformats the bibliography section of an English-language markdown draft to CMOS 18th edition, notes-and-bibliography form.
Accuracy-first, iterative, built with a karpathy/autoresearch-style dev loop.
See program.md for the goal specification and
/home/claudecode1/.claude/plans/pure-mixing-yao.md for the implementation plan.
Quick start
uv sync
uv run pytest
uv run cmos format path/to/draft.md > out.md
Layout
src/cmos/formatter.py— the iterable artifact (edited every loop iteration).src/cmos/parser.py— extracts the bibliography section from a draft.src/cmos/linter.py— deterministic CMOS 18 rule checks (versioned).src/cmos/cli.py—cmos formatentry point.harness/score.py,harness/diff.py— frozen scoring.exemplars/— TOML test corpus.tests/— pytest suite (linter, parser, formatter, cli).rough_drafts/— user-supplied messy drafts for ad-hoc iteration.logs/— per-run scores, model ids, linter version hashes.
Languages
Python
100%