Scaffold CMOS 18 reformatter: harness, linter, parser, formatter, CLI

Initial phase-1 baseline of the karpathy/autoresearch-style loop.
The formatter module is the inner-loop artifact; parser and linter
are infra. The linter carries a LINTER_VERSION hash (v0.2.0) that
will force a re-baseline on any rule change.

Components:
- harness/diff.py: case-sensitive field-level substring diff
- harness/score.py: three-axis scoring (field, linter, canary exact)
- src/cmos/linter.py: 9 CMOS 18 structural rules, each Purdue/CMOS cited
- src/cmos/parser.py: locate ## Bibliography section, split entries
- src/cmos/formatter.py: prompt + OpenAI call with caller injection
- src/cmos/cli.py: cmos format path/to/draft.md
- scripts/run_loop.py: loop runner with --fake mode for no-API runs
- exemplars/: 3 canary seed exemplars (book, journal w/DOI, web),
  sourced from chicagomanualofstyle.org quick guide

Tests: 48 passing. Fake-mode baseline scalar = 0.000 on the 3 seed
exemplars (identity caller fails the linter on every rule). This is
the floor the real GPT-5 formatter needs to improve from.
This commit is contained in:
cmos dev
2026-04-10 20:48:33 -04:00
commit 4cad38ef30
29 changed files with 2267 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
# Exemplars
Each `.toml` file is one exemplar: a messy input, a canonical structured
record, and an expected CMOS 18 bibliography string.
## Format
```toml
# IMPORTANT: all top-level keys (including expected_bibliography) must come
# BEFORE any [section] header, or TOML will absorb them into that section.
source = "Purdue OWL CMOS 18 NB PDF, p. X" # provenance, required
type = "book" # book | journal | chapter | web | ai | ...
tags = ["book", "single-author"]
canary = false # if true, exact-string match required
messy_input = "..."
expected_bibliography = "Last, First. *The Book Title*. Publisher Name, 2023."
[canonical]
# Structured fields for the field-level diff. Fields vary by type.
author = "Last, First"
title = "The Book Title"
publisher = "Publisher Name"
year = 2023
```
## Primary sources
- Purdue OWL CMOS 18 NB PDF: https://owl.purdue.edu/owl/research_and_citation/chicago_manual_18th_edition/documents/cmos-nb-20250731.pdf
- CMOS official quick guide: https://www.chicagomanualofstyle.org/tools_citationguide/citation-guide-1.html
- Widener "New in 18th" LibGuide: https://widener.libguides.com/Chicago18/New
+15
View File
@@ -0,0 +1,15 @@
# Source: CMOS official citation guide (chicagomanualofstyle.org), 18th ed.
# The canonical output is the guide's reference example verbatim.
# Rule cited: CMOS 14.30 — place of publication no longer required in 18th ed.
source = "CMOS official citation guide (chicagomanualofstyle.org/tools_citationguide/citation-guide-1.html)"
type = "book"
tags = ["book", "single-author"]
canary = true
messy_input = "yu, charles. interior chinatown. New York: Pantheon Books, 2020."
expected_bibliography = "Yu, Charles. *Interior Chinatown*. Pantheon Books, 2020."
[canonical]
author = "Yu, Charles"
title = "Interior Chinatown"
publisher = "Pantheon Books"
year = 2020
+19
View File
@@ -0,0 +1,19 @@
# Source: CMOS official citation guide (chicagomanualofstyle.org), 18th ed.
# Demonstrates: journal article with DOI, which CMOS 18 prefers over generic URL.
# Page range uses en-dash (), not hyphen (-).
source = "CMOS official citation guide (chicagomanualofstyle.org/tools_citationguide/citation-guide-1.html)"
type = "journal"
tags = ["journal", "doi", "single-author"]
canary = true
messy_input = "Kwon, Hyeyoung. \"inclusion work: children of immigrants claiming membership in everyday life.\" American Journal of Sociology, Vol. 127, Issue 6, 2022, pp. 1818-1859. DOI: 10.1086/720277"
expected_bibliography = "Kwon, Hyeyoung. \"Inclusion Work: Children of Immigrants Claiming Membership in Everyday Life.\" *American Journal of Sociology* 127, no. 6 (2022): 181859. https://doi.org/10.1086/720277."
[canonical]
author = "Kwon, Hyeyoung"
article_title = "Inclusion Work: Children of Immigrants Claiming Membership in Everyday Life"
journal = "American Journal of Sociology"
volume = 127
issue = 6
year = 2022
pages = "181859"
doi = "https://doi.org/10.1086/720277"
+16
View File
@@ -0,0 +1,16 @@
# Source: CMOS official citation guide (chicagomanualofstyle.org), 18th ed.
# Demonstrates: web page with "Effective" date (rather than access date).
# Site owner / corporate author sits in the author slot when no personal author exists.
source = "CMOS official citation guide (chicagomanualofstyle.org/tools_citationguide/citation-guide-1.html)"
type = "web"
tags = ["web", "corporate-author"]
canary = true
messy_input = "google, \"privacy policy,\" privacy & terms, effective nov 15 2023, policies.google.com/privacy"
expected_bibliography = "Google. \"Privacy Policy.\" Privacy & Terms. Effective November 15, 2023. https://policies.google.com/privacy."
[canonical]
author = "Google"
title = "Privacy Policy"
site = "Privacy & Terms"
date = "November 15, 2023"
url = "https://policies.google.com/privacy"