Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
95fcb9d
identity: reset to 0.1.0a1/Alpha and reconcile every claim with STATU…
ebt55 Jul 29, 2026
cab3939
testkit: a missing oracle is a skip, a broken one is an error (corpus…
ebt55 Jul 29, 2026
a3139f1
scripts: one command provisions the harness, and probes what it found
ebt55 Jul 29, 2026
11ee43f
git: keep shell scripts LF on checkout
ebt55 Jul 29, 2026
0e368d4
golden_ir: record the environment a golden was frozen in
ebt55 Jul 29, 2026
03c6948
golden_ir: re-freeze on Linux to attach the manifest -- provably cont…
ebt55 Jul 29, 2026
b8bcf30
harness: count CJK by character, not by whitespace (c4_i18n recall .8…
ebt55 Jul 29, 2026
41e5064
testkit: gate on NEW failures, so the gate can fail at all (exit 1 ->…
ebt55 Jul 29, 2026
98d8e60
ci: the gate can now fail, so stop ignoring it
ebt55 Jul 29, 2026
d4ca28f
docs: record the Linux/CI baseline and close M1
ebt55 Jul 29, 2026
24376a7
testkit: a span-level microscope, and --only, for the code-heavy pair
ebt55 Jul 29, 2026
34d9183
docs: the parity gate is the contract, the golden IR is a microscope
ebt55 Jul 29, 2026
60b9c29
pdfium: put back the leading indentation PDFium does not report (c7_c…
ebt55 Jul 29, 2026
dadb36e
SESSIONS: 03_tech traced to the stroke-bbox convention; the fix measu…
ebt55 Jul 29, 2026
eced9ee
docs: CI is the number of record, and it has now actually run
ebt55 Jul 29, 2026
52ced06
testkit: probe which space PDFium reports path points in (612 paths, …
ebt55 Jul 29, 2026
c0d09b7
pdfium: put path geometry in page space (c7_code .59 -> .76, 8 regres…
ebt55 Jul 29, 2026
bb39e2a
testkit: plot the distributions the block-split threshold separates (…
ebt55 Jul 29, 2026
c10b3a7
pdfium: split blocks on the BODY pitch, not the median (8 regressions…
ebt55 Jul 29, 2026
49a12ff
pdfium: take x from the metric box, as y already did (6 regressions -…
ebt55 Jul 29, 2026
41770e1
pdfium: a span ends where the style ends, and a generated space has a…
ebt55 Jul 29, 2026
9976d2a
pdfium: drop the end-of-line space PDFium invents (03_tech text diff …
ebt55 Jul 29, 2026
4a5d2a3
pdfium: one space is one space, however far justification stretches it
ebt55 Jul 29, 2026
d2a0356
pdfium: body pitch per type size, not per page (3 regressions -> 2)
ebt55 Jul 29, 2026
aeec173
testkit: histogram the vertical error, and locate the last constant o…
ebt55 Jul 29, 2026
1ac6304
git: ignore the planning docs by name shape, not one at a time
ebt55 Jul 29, 2026
b1c90d2
infer: the granted line-box escalation, built and reverted -- fallbac…
ebt55 Jul 29, 2026
0cd7d11
docs: ROADMAP.md, and bring every committed doc up to where the proje…
ebt55 Jul 29, 2026
6d8c47b
gate: make green mean green -- fail-closed evidence, and one product …
ebt55 Jul 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Shell scripts must keep LF endings even when checked out on Windows: a CRLF
# shebang line makes the kernel look for an interpreter named "bash\r", and the
# error it produces ("bad interpreter: No such file or directory") points at
# the interpreter rather than at the line ending. scripts/bootstrap.sh is
# authored on Windows here and run on Linux, so this is not hypothetical.
*.sh text eol=lf

# Same reasoning for anything a Linux runner executes or parses strictly.
*.yml text eol=lf
*.yaml text eol=lf
99 changes: 66 additions & 33 deletions .github/workflows/gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,28 @@
# everyone can reproduce -- so CI is the number of record and local runs are
# indicative.
#
# Two lanes (testkit/runall.py lanes): refine OFF is the uncontaminated
# converter number; refine ON is the product default. refine() tunes against
# the same renderer the gate measures with, so only the pair is meaningful.
# Two lanes (testkit/runall.py): `raw` is the uncontaminated converter number,
# `product` is exactdoc.options.PRODUCT -- the profile the API, the CLI and every
# published number all share. refine() tunes against the same renderer the gate
# measures with, so only the pair is meaningful, and **both** lanes gate the exit
# code. Gating on the refined lane alone meant the control lane, whose entire
# purpose is to be untainted, was the one nobody had to answer for.
#
# The purity test is a hard failure. The gate lanes are reporting-only until
# the first Linux run establishes the baseline (thresholds so far were
# calibrated on Windows fonts); once pinned, drop the continue-on-error.
# Every step here is fail-closed. That is the whole design: a green check must
# mean that all 16 manifest documents existed, the renderer answered, every
# required metric was computed, nothing regressed past its recorded number, and
# the backend policy still describes reality. It previously could mean none of
# those things -- see the docstrings in testkit/gate.py for the list, each entry
# of which is now a test in tests/test_gate_mutations.py.
#
# Provisioning is scripts/bootstrap.sh, the same command a contributor runs, so
# CI cannot drift away from the documented setup without going red. --strict
# makes a missing oracle a failure.
#
# The dependency versions come from uv.lock (--frozen). The goldens are pinned
# to the PyMuPDF version -- measured: 1.26 and 1.24 both put 02_research_paper
# p2 at 4 blocks where 1.28 puts 7 -- so an unpinned resolve would fail the
# golden step for a reason that has nothing to do with this repository's code.
name: gate

on:
Expand All @@ -24,50 +39,68 @@ on:
jobs:
gate:
runs-on: ubuntu-24.04
timeout-minutes: 45
timeout-minutes: 90
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install LibreOffice + fonts (the pinned oracle)
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends libreoffice-writer fonts-liberation
soffice --version
- name: Install uv (uv.lock is the pinned truth)
uses: astral-sh/setup-uv@v5
with:
enable-cache: true

- name: Install package + test deps
run: |
python -m pip install -q -e .[test]
python -m pip install -q pytest
- name: Provision the oracles (LibreOffice, Chromium, fonts) + deps
run: bash scripts/bootstrap.sh --strict

- name: Generate corpora (ReportLab + Chromium/WeasyPrint-class dialects)
# --strict here too: this printed "SKIPPED 8 document(s)" and "gate numbers
# are NOT comparable", then exited 0, and the next step scored the 8 that
# existed against a 16-document baseline. Prose the next step ignores is
# not a safeguard.
- name: Generate the corpus (16 documents, or fail)
run: |
python corpus/make_corpus.py
python testkit/gen_corpus.py testkit/adv
uv run python testkit/gen_corpus.py testkit/adv --strict
uv run python corpus/make_corpus.py

- name: Purity - writing the same layout twice must be byte-identical
run: python tests/test_purity.py
- name: Corpus manifest - is this the corpus the baseline describes?
run: uv run python testkit/corpus_manifest.py verify

- name: Unit tests (write purity, corpus degradation, gate mutations)
run: |
uv run python tests/test_purity.py
uv run python tests/test_corpus_degradation.py
uv run python tests/test_gate_mutations.py

- name: Golden IR - the parser's output must not drift
# Also the acceptance test for any future permissive-parser backend:
# a replacement is correct when it reproduces these.
run: python testkit/golden_ir.py verify
run: uv run python testkit/golden_ir.py verify

- name: Fidelity gate, both lanes, fail closed
run: uv run python testkit/runall.py

- name: Fidelity gate, both lanes
continue-on-error: true # reporting until the Linux baseline is pinned
env:
REFINE: lanes
run: python testkit/runall.py testkit/adv corpus/pdfs
# No longer continue-on-error. It was reporting-only "until the swap
# lands", which made the number it exists to drive the one number nothing
# depended on. The policy the two accepted shortfalls were ratified under
# now lives in testkit/parity_policy.json with numeric floors, so the
# executable rule and the ratified rule are the same rule and the step can
# be required.
- name: Backend parity - the licence-swap verdict
run: uv run python testkit/backend_parity.py

- name: Evidence - one artifact every published number traces to
if: always()
run: uv run python testkit/evidence.py --out testkit/batch/evidence.json

- name: Upload lane results
- name: Upload lane results and evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: gate-results
path: |
testkit/batch/lane_norefine/results.json
testkit/batch/lane_refine/results.json
if-no-files-found: warn
testkit/batch/evidence.json
testkit/batch/lane_raw/results.json
testkit/batch/lane_raw/verdict.json
testkit/batch/lane_product/results.json
testkit/batch/lane_product/verdict.json
if-no-files-found: error
17 changes: 16 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ dist/
.vscode/
.idea/

# Written by scripts/bootstrap.sh: discovered oracle paths, and any tool it had
# to fetch because the distribution does not package it.
scripts/env.sh
.tools/

# Generated test corpora and conversion outputs (all reproducible)
testkit/adv/
testkit/real/
Expand Down Expand Up @@ -44,5 +49,15 @@ client_secret*
# personal test inputs -- never publish
my_samples/

# private working notes -- not for publication
# Private working notes -- not for publication. The planning and review
# documents all share the form "exactdoc — <something>.md" and live in the repo
# root beside the tracked docs, which is one `git add -A` away from publishing
# them. The tracked docs (README, STATUS, THEORY, FINDINGS) do not carry the
# prefix, so this pattern cannot catch them by accident.
Executor Advisory.md
exactdoc — *.md
*Execution Plan*.md
# The em-dash pattern above missed `exactdoc-production-readiness-plan.md`, which
# is the same kind of document under a hyphen. Match the suffix as well: no
# tracked doc ends in -plan.md.
*-plan.md
6 changes: 6 additions & 0 deletions FINDINGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
> in §1 are historical. Two claims here were later falsified by measurement and
> are marked inline.
>
> "v1.1" is a pre-release internal label from before this repository had
> versioned releases. It corresponds to no tag and no published artifact; the
> version line starts at `0.1.0a1` (see the README's Versions table). The
> 18-document corpus measured here is also not the current one — today's gate
> corpus is 16 generated documents.
>
> For current state: **[STATUS.md](STATUS.md)**. For the design: **[THEORY.md](THEORY.md)**.

18 documents, 4 producer engines, measured with `testkit/` (shares no code with
Expand Down
Loading
Loading