Skip to content

Commit 02b06ea

Browse files
committed
research(pacseries): v0.3 packaging, consistency pass, and method framing
Prepare PACSeries v0.3 (Papers 7-12) for release: fix content/consistency issues, run a de-LLM-ism voice pass, and build full reproducibility packages (Code/Data/Figures/ meta/README/tex) to the v0.2 gold standard. Papers 7-11 run-verified; Paper 12 data-gated. Adversarial verification caught and corrected six over-attributions (logged in the changelog as Imperfection-Engine collapse events), incl. the Paper 11 Bell saturation and Paper 8 bounce-time conflations. Added HOW_TO_READ.md and per-paper epistemic-status blocks stating the evolving-program / A-B-C-tiered / reproducible stance. No changes to published v0.1/v0.2. New tooling: md_to_tex.py (pandoc-free).
1 parent 3579dbf commit 02b06ea

297 files changed

Lines changed: 71347 additions & 156 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# PACSeries v0.3: content pass, de-slop, packaging, and method framing
2+
3+
Prepared PACSeries v0.3 (Papers 7–12) for release. Scope is locked to the new
4+
Papers 7–12; no changes to the published v0.1/v0.2 packages.
5+
6+
## Content & consistency
7+
- Fixed factual/consistency issues across all six drafts (cross-reference numbering,
8+
misattributed experiment IDs, score labels, a self-citation, and metadata).
9+
- Corrected DOI labels (concept 15783623 vs v0.2 record 18743674).
10+
- Added the previously-omitted Type-A verification numbers to Paper 10 (§4.1 commutation
11+
relations to 1.1e-16; §6.3 Killing signature (3,3)→(1,3), ds² across 135 transforms,
12+
Schur uniqueness).
13+
14+
## Voice
15+
- De-LLM-ism pass across all six papers: removed aphoristic closers, caps emphasis,
16+
reveal-cadence, hype adjectives, and theatrical em-dashes. No claims, numbers, or
17+
structure changed; genuine thesis headings and the "honest failures" vocabulary kept.
18+
19+
## Packaging (to the v0.2 gold standard)
20+
- Built full reproducibility packages for all six papers: `Code/experiments` (verbatim
21+
source scripts) + `reproduce.py` + `trace.yaml` + `requirements.txt` +
22+
`generate_figures.py`, `Data/results`, `Figures/`, `meta.yaml`, `README.md`, `paper.tex`.
23+
- Model = repo-relative: `reproduce.py` locates `foundational/experiments` and injects the
24+
home-milestone `core/` onto PYTHONPATH; scripts run unmodified.
25+
- Run-verified: Papers 7, 8, 9, 10, 11 execute end-to-end with scores matching the papers
26+
(including documented honest failures). Paper 12 is data-gated (needs external SDSS/XQR
27+
catalogs) and is packaged but not run here.
28+
- New reusable tooling at the series root: `md_to_tex.py` (pandoc-free md→LaTeX).
29+
30+
## Corrections logged (Imperfection Engine — collapse events found during verification)
31+
Adversarial packaging (every headline number checked against its result JSON) surfaced
32+
six over-attributions/mismatches, all corrected:
33+
- Paper 11: CHSH "Tsirelson saturation 2.828" was the ideal SU(2) generator; the
34+
graph-derived (orbit-Laplacian) rotation reaches 2.514 (88.8%). Abstract/§7 corrected.
35+
- Paper 8: bounce time is 1.0 t_P (exp_11), not 0.72 (the MVAE cascade tick, exp_03);
36+
§10.2 derivation and abstract corrected. Hawking CV 7.8e-17→1.74e-16; Page remnant
37+
0.3/1.2→3.8/38 nats.
38+
- Paper 10: ds² preservation is 2.9e-6 across 135 transforms (not 3e-16 from a 5-transform
39+
run); exp_16 (0/4) added to the disclosed failures.
40+
- Paper 7: dark self-interaction σ/m ≈ 6.9e-20 (was "< 1e-20"); M6 score drift (34/40 vs a
41+
latest 35/40 run) noted in the package README.
42+
43+
## Method framing
44+
- Added `PACSeries/HOW_TO_READ.md` — a methodological (not manifesto) statement of the
45+
Imperfection-Engine stance: evolving program, A/B/C tiering, failures reported,
46+
corrections logged, everything reproducible.
47+
- Added a consistent "Epistemic status" block to all six papers and linked the note from
48+
the series README.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# How to Read the PACSeries
2+
3+
The PACSeries is an evolving research program, not a finished theory. This note states plainly how the work is built and how to weigh its claims — a frame we would rather make explicit than have you infer.
4+
5+
## The stance
6+
7+
"Is it perfect?" is the wrong question to ask of any physical framework. Every theory in the history of physics has been a successively-less-wrong model; Newton was not wrong, he was less close. The PACSeries is built to *move* — to be sharpened by scrutiny, to log its own corrections, and to converge rather than to arrive. We do not claim to be right. We try to be less wrong than the current picture, and to make every step checkable so you can judge for yourself.
8+
9+
## What that means in practice
10+
11+
1. **Results are tiered by derivation type.** Every quantitative claim is labeled:
12+
- **Type A (structural)** — follows from the axioms through theorems, with at most one empirical step. It would produce the same result without knowing the target value.
13+
- **Type B (identified)** — a clean expression matches a known value after a few empirical identifications.
14+
- **Type C (pattern-matched)** — found by searching against known values, and acknowledged as such.
15+
16+
The tier matters more than any single number. The companion `derivation_classification.md` gives the full chain for each result.
17+
18+
2. **Failures are reported, not hidden.** Every paper has a "what fails" section. One pre-registered prediction has already been falsified against data (Paper 12, against ~443,000 quasar absorption systems). A framework that can die, and says so, is behaving like physics.
19+
20+
3. **Corrections are logged.** When a result turns out to be a curve-fitting artifact or a tautological test, it is recorded in the Epistemic Corrections Registry (`EPISTEMIC_CORRECTIONS_REGISTRY.md`, repository root) as a *collapse event* — the mechanism by which the framework improves, not something to bury.
21+
22+
4. **Everything is reproducible.** Each paper ships the code, data, and figure-generation that produced its numbers, traced to source (`Code/`, `Data/`, and `Code/trace.yaml`). You do not have to trust the prose; you can run it.
23+
24+
## How to weigh a given claim
25+
26+
Check its tier first. A Type-A result is a theorem plus a stated postulate — to reject it you must reject the axioms or find the error in the proof. A Type-C result is a pattern whose weight lies in the *joint* structure across independent domains, not in any individual match; read it with the look-elsewhere effect in mind. Read the precision tables and the failure sections together — neither is complete without the other.
27+
28+
---
29+
30+
*The series is released under this frame deliberately. To declare it finished would stop the motion; to keep it open, tiered, and falsifiable is to let it improve. See also `state_of_the_pac_series.md` for the series-wide classification of every result.*

foundational/docs/preprints/PACSeries/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
The PACSeries establishes Dawn Field Theory through clean derivation from established science, measurement with error bounds, and honest separation of established results from speculation. Papers are numbered by logical dependency, not historical order.
99

10+
**New readers start here:** [How to Read the PACSeries](HOW_TO_READ.md) — how the work is built, how its claims are tiered (Type A/B/C), and how to weigh them. This is an evolving research program, not a finished theory.
11+
1012
## Versions
1113

1214
### [v0.2/](v0.2/) — Current (February 2026)
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
#!/usr/bin/env python3
2+
"""
3+
md_to_tex.py — Convert a PACSeries paper.md into paper.tex.
4+
5+
Standalone (no pandoc). Handles the constructs the PACSeries papers use:
6+
headings, paragraphs, $...$/$$...$$ math (passthrough), pipe tables (booktabs),
7+
ordered/unordered lists, bold/italic/inline-code, links, and horizontal rules.
8+
Math and inline-code spans are protected before LaTeX escaping so their contents
9+
are never mangled.
10+
11+
Compiles with xelatex or lualatex (unicode passthrough via unicode-math), or
12+
pdflatex (unicode chars in prose may need the fallback below).
13+
14+
Usage:
15+
python md_to_tex.py <paper_dir> --number N --date "May 2026"
16+
# writes <paper_dir>/paper.tex from <paper_dir>/paper.md
17+
"""
18+
import re
19+
import sys
20+
import argparse
21+
from pathlib import Path
22+
23+
PREAMBLE = r"""\documentclass[11pt,a4paper]{article}
24+
\usepackage{iftex}
25+
\ifPDFTeX
26+
\usepackage[T1]{fontenc}
27+
\usepackage[utf8]{inputenc}
28+
\usepackage{textcomp}
29+
\else
30+
\usepackage{unicode-math}
31+
\defaultfontfeatures{Scale=MatchLowercase}
32+
\fi
33+
\usepackage{amsmath,amssymb,amsthm}
34+
\usepackage{booktabs}
35+
\usepackage{longtable}
36+
\usepackage{array}
37+
\usepackage{graphicx}
38+
\usepackage[margin=1in]{geometry}
39+
\usepackage{xcolor}
40+
\usepackage{hyperref}
41+
\hypersetup{colorlinks=true,linkcolor=blue!60!black,citecolor=green!50!black,urlcolor=blue!60!black}
42+
\usepackage{fancyhdr}
43+
\pagestyle{fancy}
44+
\fancyhf{}
45+
\fancyhead[L]{\small PACSeries Paper %(number)s}
46+
\fancyhead[R]{\small Dawn Field Institute}
47+
\fancyfoot[C]{\thepage}
48+
\renewcommand{\headrulewidth}{0.4pt}
49+
\setlength{\parindent}{0pt}
50+
\setlength{\parskip}{6pt plus 2pt minus 1pt}
51+
\providecommand{\tightlist}{\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
52+
53+
\title{%(title)s}
54+
\author{Peter Groom \\ Dawn Field Institute}
55+
\date{%(date)s}
56+
57+
\begin{document}
58+
\maketitle
59+
"""
60+
61+
FOOTER = "\n\\end{document}\n"
62+
63+
64+
def escape_tex(s):
65+
# s has NO math/code spans (already protected). Escape LaTeX specials.
66+
out = []
67+
for ch in s:
68+
if ch == '\\':
69+
out.append(r'\textbackslash{}')
70+
elif ch in '&%#_${}':
71+
out.append('\\' + ch)
72+
elif ch == '~':
73+
out.append(r'\textasciitilde{}')
74+
elif ch == '^':
75+
out.append(r'\textasciicircum{}')
76+
else:
77+
out.append(ch)
78+
return ''.join(out)
79+
80+
81+
def inline(text, store):
82+
"""Protect math/code, escape, then apply md inline formatting, then restore."""
83+
# 1. protect $$...$$, $...$, `code`
84+
def protect(pat, m):
85+
store.append(m.group(0) if pat != 'code' else '\\texttt{' + escape_tex(m.group(1)) + '}')
86+
return f'\x00{len(store)-1}\x00'
87+
text = re.sub(r'\$\$.*?\$\$', lambda m: protect('math', m), text, flags=re.S)
88+
text = re.sub(r'(?<!\\)\$.+?(?<!\\)\$', lambda m: protect('math', m), text)
89+
text = re.sub(r'`([^`]+)`', lambda m: protect('code', m), text)
90+
# 2. escape the remaining prose
91+
text = escape_tex(text)
92+
# 3. md inline -> latex (operate on escaped text; ** and * survive escaping)
93+
text = re.sub(r'\*\*(.+?)\*\*', r'\\textbf{\1}', text)
94+
text = re.sub(r'(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)', r'\\emph{\1}', text)
95+
# links [t](u) -> \href{u}{t} (u was escaped: unescape _ and # inside url)
96+
def link(m):
97+
t, u = m.group(1), m.group(2)
98+
u = u.replace(r'\_', '_').replace(r'\#', '#').replace(r'\%', '%').replace(r'\&', '&')
99+
return r'\href{' + u + '}{' + t + '}'
100+
text = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', link, text)
101+
# 4. restore protected spans
102+
text = re.sub(r'\x00(\d+)\x00', lambda m: store[int(m.group(1))], text)
103+
return text
104+
105+
106+
def _split_cells(r):
107+
# protect $...$ math (which may contain '|') and escaped \| before splitting
108+
spans = []
109+
def prot(m):
110+
spans.append(m.group(0)); return f'\x01{len(spans)-1}\x01'
111+
r2 = re.sub(r'(?<!\\)\$.+?(?<!\\)\$', prot, r)
112+
r2 = r2.replace(r'\|', '\x02')
113+
parts = [p.strip() for p in r2.strip().strip('|').split('|')]
114+
out = []
115+
for p in parts:
116+
p = p.replace('\x02', r'\|')
117+
p = re.sub(r'\x01(\d+)\x01', lambda m: spans[int(m.group(1))], p)
118+
out.append(p)
119+
return out
120+
121+
122+
def convert_table(rows):
123+
# rows: list of raw md table lines (including header + separator)
124+
cells = [_split_cells(r) for r in rows]
125+
header = cells[0]
126+
body = cells[2:] # skip separator row (cells[1])
127+
ncol = len(header)
128+
align = 'l' * ncol
129+
out = [r'\begin{longtable}[]{@{}' + align + r'@{}}', r'\toprule']
130+
store = []
131+
out.append(' & '.join(inline(h, store) for h in header) + r' \\')
132+
out.append(r'\midrule\endhead')
133+
for row in body:
134+
row = (row + [''] * ncol)[:ncol]
135+
out.append(' & '.join(inline(c, store) for c in row) + r' \\')
136+
out.append(r'\bottomrule')
137+
out.append(r'\end{longtable}')
138+
return '\n'.join(out)
139+
140+
141+
def convert(md, title):
142+
lines = md.split('\n')
143+
out = []
144+
i = 0
145+
n = len(lines)
146+
store = []
147+
seen_title = False
148+
while i < n:
149+
line = lines[i]
150+
stripped = line.strip()
151+
152+
# fenced blocks not expected; skip if present
153+
if stripped.startswith('```'):
154+
i += 1
155+
buf = []
156+
while i < n and not lines[i].strip().startswith('```'):
157+
buf.append(lines[i]); i += 1
158+
i += 1
159+
out.append(r'\begin{verbatim}')
160+
out.extend(buf)
161+
out.append(r'\end{verbatim}')
162+
continue
163+
164+
# display math block
165+
if stripped.startswith('$$') and stripped.endswith('$$') and len(stripped) > 3:
166+
out.append(r'\[' + stripped[2:-2].strip() + r'\]')
167+
i += 1; continue
168+
if stripped == '$$':
169+
i += 1; buf = []
170+
while i < n and lines[i].strip() != '$$':
171+
buf.append(lines[i]); i += 1
172+
i += 1
173+
out.append(r'\[' + '\n'.join(buf) + r'\]')
174+
continue
175+
176+
# headings
177+
m = re.match(r'^(#{1,6})\s+(.*)$', stripped)
178+
if m:
179+
level = len(m.group(1)); htext = m.group(2)
180+
if level == 1 and not seen_title:
181+
seen_title = True # title handled in preamble
182+
i += 1; continue
183+
cmd = {1: 'section*', 2: 'section*', 3: 'subsection*',
184+
4: 'subsubsection*', 5: 'paragraph', 6: 'subparagraph'}.get(level, 'subsection*')
185+
out.append('\\%s{%s}' % (cmd, inline(htext, store)))
186+
i += 1; continue
187+
188+
# horizontal rule
189+
if re.match(r'^-{3,}$', stripped) or re.match(r'^\*{3,}$', stripped):
190+
out.append(r'\begin{center}\rule{0.5\linewidth}{0.4pt}\end{center}')
191+
i += 1; continue
192+
193+
# table (a line with | and next line is separator)
194+
if '|' in line and i + 1 < n and re.match(r'^\s*\|?[\s:\-|]+\|?\s*$', lines[i+1]) and '-' in lines[i+1]:
195+
tbl = [lines[i], lines[i+1]]
196+
i += 2
197+
while i < n and '|' in lines[i] and lines[i].strip():
198+
tbl.append(lines[i]); i += 1
199+
out.append(convert_table(tbl))
200+
continue
201+
202+
# unordered list
203+
if re.match(r'^\s*[-*]\s+', line):
204+
out.append(r'\begin{itemize}\tightlist')
205+
while i < n and re.match(r'^\s*[-*]\s+', lines[i]):
206+
item = re.sub(r'^\s*[-*]\s+', '', lines[i])
207+
out.append(r'\item ' + inline(item, store))
208+
i += 1
209+
out.append(r'\end{itemize}')
210+
continue
211+
212+
# ordered list
213+
if re.match(r'^\s*\d+\.\s+', line):
214+
out.append(r'\begin{enumerate}\tightlist')
215+
while i < n and re.match(r'^\s*\d+\.\s+', lines[i]):
216+
item = re.sub(r'^\s*\d+\.\s+', '', lines[i])
217+
out.append(r'\item ' + inline(item, store))
218+
i += 1
219+
out.append(r'\end{enumerate}')
220+
continue
221+
222+
# blank line
223+
if stripped == '':
224+
out.append('')
225+
i += 1; continue
226+
227+
# paragraph (gather until blank/structural)
228+
para = [line]
229+
i += 1
230+
while i < n and lines[i].strip() != '' and not re.match(r'^(#{1,6}\s|\s*[-*]\s|\s*\d+\.\s|\$\$|```|-{3,}$)', lines[i]) and not ('|' in lines[i] and i+1 < n):
231+
para.append(lines[i]); i += 1
232+
out.append(inline(' '.join(p.strip() for p in para), store))
233+
234+
return '\n'.join(out)
235+
236+
237+
def main():
238+
ap = argparse.ArgumentParser()
239+
ap.add_argument('paper_dir')
240+
ap.add_argument('--number', required=True)
241+
ap.add_argument('--date', default='2026')
242+
args = ap.parse_args()
243+
244+
pdir = Path(args.paper_dir)
245+
md = (pdir / 'paper.md').read_text()
246+
# title = first '# ' heading
247+
tm = re.search(r'^#\s+(.*)$', md, flags=re.M)
248+
title = tm.group(1).strip() if tm else pdir.name
249+
store = []
250+
title_tex = inline(title, store)
251+
252+
body = convert(md, title)
253+
tex = (PREAMBLE % {'number': args.number, 'title': title_tex, 'date': args.date}) + body + FOOTER
254+
(pdir / 'paper.tex').write_text(tex)
255+
print(f"wrote {pdir/'paper.tex'} ({len(tex.splitlines())} lines)")
256+
257+
258+
if __name__ == '__main__':
259+
main()

0 commit comments

Comments
 (0)