arrolio 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0b6af09c229c5ee869a2e052c61933ccf441cccf02ace5b965acaf2dcdfa277
4
- data.tar.gz: 650539bee9ae880208f9986e26ccc4a9ffe38acbf773a47a1471a54cfb43f688
3
+ metadata.gz: 057f22d28911ebd5fb250d0a3ee3aae065a493c2c8aee0a5ff329a138da38674
4
+ data.tar.gz: 8477b14736601c87ee24c690aa867ef175de94568ef866b48d260948c3d98116
5
5
  SHA512:
6
- metadata.gz: c8ea9131445f66cdcae37550aebb04036bcbedc995e713220f3e2c76391b2c35e6daa6f71b6e2d32a51f6ad33b526c36e6d2fdc5fac5dd92d0440b31bb7c2a7c
7
- data.tar.gz: 19a06bdb5726413dcea2de7022eab8ede88c9a10133ad78545211eb294e1ec5884bd47c7753fdaed9ddc6ef5afac1e71b177fdc30b6061f5af39a03ff894b30e
6
+ metadata.gz: 2aef88dd6df44e8aef2be218f34f53de0e332ecfb94bc2ef5aa8a87f0221fab634ac05ad0a900997fc1ebb870529626a464eeaa302c7f3e19d1b05664bfd7e90
7
+ data.tar.gz: b984b3dae46396305d96e5c6977a24992c4ddae317be8a4682fafed9de46a35a7e2442dbc418147c77afb943ba7981c6b8be28b562b85723fe5624b3242b6c7c
data/CLAUDE.md CHANGED
@@ -53,16 +53,17 @@ PDF bytes (via Pdfrb)
53
53
 
54
54
  Each layer is independently testable. Keep layer boundaries airtight: Content knows nothing about pages or PDF; Engine knows nothing about PDF bytes; Renderer knows nothing about layout algorithms.
55
55
 
56
- ## Project state (as of 2026-08-03)
56
+ ## Project state (as of 2026-09-01)
57
57
 
58
- Generic config-driven pipeline works end-to-end: the OIML r060/1 fixture renders to a 25-page A4 PDF (~194 KB) via `Arroolio::ConfigDrivenPipeline` pointed at `flavors/oiml/`. 232 specs pass.
58
+ The generic config-driven pipeline renders the OIML r060/1 fixture to a 28-page A4 PDF matching the mn2pdf v2.55 reference at **68.92% text parity, 28/28 pages** (`bundle exec rake parity:check`). 452 specs, 0 rubocop offenses, 214 files.
59
59
 
60
60
  What's in the gem (core, flavor-agnostic):
61
61
  - `lib/arrolio/{content,style,layout_spec,font,font_metrics,glyph_measurer,inline_run,text_layout,flowable,flowables,frame,flow_context,engine,output,renderer,harness,flavor}/`
62
- - `lib/arrolio/generic_adapter.rb` — reads `adapter_rules.yml`, parses any flavor's XML into `Content::Document`.
63
- - `lib/arrolio/generic_flow_builder.rb` — reads `flow_rules.yml`, builds flowables for any flavor.
64
- - `lib/arrolio/config_driven_pipeline.rb` — orchestrates adapter + flow builder + engine + renderer + ToC.
65
- - `lib/arrolio/asset_resolver.rb`, `lib/arrolio/toc_builder.rb`generic helpers.
62
+ - `lib/arroolio/generic_adapter.rb` — dispatch + document glue; per-concern conversion lives in included seams under `lib/arroolio/generic_adapter/` (FootnoteExtraction, TableConversion, InlineRunCollection, HeadingExtraction, ListConversion, MetadataExtraction, DocumentExtraction). Adding an element family = a module + one include.
63
+ - `lib/arroolio/generic_flow_builder.rb` — `build()` + dispatch; per-family emission seams under `lib/arroolio/generic_flow_builder/` (Sequences, Terms, Notes, Figures, Lists, Bibliography, Tables).
64
+ - `lib/arroolio/config_driven_pipeline.rb` — orchestrates adapter + flow builder + engine + renderer + ToC; resolves fonts via fontist (`FontScanner`).
65
+ - `lib/arroolio/renderer/pdf.rb` — page emission; Pdfrb coupling points in `lib/arroolio/renderer/pdf/` (FontEmbedding, Assets, Metadata). The renderer never measures glyph widths `Line::PlacedRun` carries `chunk_widths` from the breakers.
66
+ - `lib/arroolio/asset_resolver.rb`, `lib/arroolio/toc_builder.rb` — generic helpers (both with direct specs).
66
67
  - `exe/arrolio2pdf` — generic CLI taking a flavor directory argument.
67
68
  - `scripts/xsl_to_config.rb` — generates all three flavor YAML files from an XSL stylesheet.
68
69
  - `data/arrolio/` — AFM metrics + glyphlist for the 14 PDF standard fonts (core data, not flavor data).
@@ -71,18 +72,13 @@ What's outside the gem (flavor artifacts):
71
72
  - `flavors/oiml/{layout_spec,adapter_rules,flow_rules}.yml` — generated by `xsl_to_config.rb` from the authoritative XSL at `~/src/mn/metanorma-taste/data/oiml/oiml.xsl`.
72
73
  - `spec/fixtures/flavors/sample/` — synthetic flavor-neutral fixture for the gem's tests.
73
74
 
74
- What's deferred (intentionally — see `TODO.complete/`):
75
- - TODO 53: second flavor spike (proves the generic design works beyond OIML).
76
- - TODO 54: `flavors/<name>/manifest.yml` contract.
77
- - TODO 55: header/footer style in `layout_spec.yml` (currently hardcoded in renderer).
78
- - TODO 56: split `GenericAdapter` into MECE per-element converters.
79
- - TODO 57: strict `Content::Document#sections` typing (only `Section[]`).
80
- - TODO 58: flavor packaging convention (`arrolio-<flavor>` gems).
81
- - TODO 59: XSL converter profiles (metanorma, dita, docbook).
82
- - TODO 60: footnote / note-hanging-indent / example-body-margin fidelity.
83
- - TODO 61: typed error model + strict mode.
84
- - TODO 62: font resolution via fontist (currently absolute paths in YAML).
85
- - Plus the older TODO.implementation items (Knuth-Plass, PageSequenceMaster, table layout, etc.).
75
+ What's open (intentionally — see `TODO.complete/`, frontmatter `status:` is authoritative):
76
+ - TODO 87: odd/even page templates beyond header parity (headers mirror; templates don't).
77
+ - TODO 88: hyphenation support.
78
+ - TODO 90: MathML mfrac true stacking (the open piece).
79
+ - TODO 93: figure text searchability (figures render as images; the reference's figure text extracts).
80
+ - TODO 96: pagination drift parity — the master ledger: remaining region deficits, keep-rules negative results (the reference does NOT enforce widows; term entries are NOT atomic), the heading-gap coupled-landing recipe, and the C2 margin-unification decode (a dedicated re-tuning session, not a release-day change).
81
+ - TODOs 53-62 are DONE (second flavor spike, manifest contract, header/footer config, adapter MECE, strict typing, packaging docs, XSL profiles, footnote fidelity, typed errors, fontist).
86
82
 
87
83
  The TODO files in `TODO.complete/` and `TODO.implementation/` are the roadmap. `TODO.complete/README.md` covers the parity roadmap; `TODO.implementation/README.md` covers the foundation phase plan.
88
84
 
@@ -137,8 +133,9 @@ When extending any layer, apply OCP/DRY/MECE strictly:
137
133
  ## Renderer/Pdfrb coupling notes
138
134
 
139
135
  - `Renderer::Pdf#render_page` deliberately points each pdfrb page's `Resources` Hash at the catalog's. Pdfrb's `Fonts#add` attaches fonts to the *catalog* Resources, but each Page shadows with its own empty Hash — without this workaround, fonts are invisible to readers.
140
- - `Renderer::FontRegistry` memoises font family name Pdfrb resource Symbol per render pass. Falls back to Helvetica for unknown families so the render never crashes mid-document. TODO 62 makes this strict.
141
- - TODO 55 moves the header/footer visual style (Arial 9pt + 0.5pt border, currently hardcoded in the renderer) into `layout_spec.yml` so each flavor controls its own header/footer look.
136
+ - Margin contract (see `Flowable`'s doc): TextFlowable (and HeadingFlowable) count `space_before/after` inside height/emit; List/Image/Table-based flowables do not — spacing around them travels as explicit Spacers. The engine collapses via `Engine::MarginCollapse`; do NOT unify without a dedicated re-tuning session (decoded in TODO 96).
137
+ - Header/footer styling comes from `layout_spec.yml` (`header_footer:` block); font resolution goes through fontist (`FontScanner`) with AFM fallback for the 14 standard fonts.
138
+ - Parity workflow: `bundle exec rake parity:check` / `parity:diff PAGE=N`; drift-map tooling and diagnostic cautions live in TODO 96.
142
139
 
143
140
  ## Key files to read first
144
141
 
@@ -512,6 +512,28 @@ or the layout differs from the pipeline.
512
512
  gaps reproduce (p8 69 vs 76) but nets -6pp; still blocked by the
513
513
  p9-p15 fill mismatch.
514
514
 
515
+ ## C2 margin unification — attempt executed and reverted (2026-08-31)
516
+
517
+ Round-5 attempt with the prepared MarginCollapse seam. The
518
+ implementation (margins inside every List/Image/Note/Table
519
+ flowable, CSS inset = max(pa,b) - pa + b, page-top exception,
520
+ Spacer workarounds deleted, block-style neutralization for the
521
+ dead note/list margins) measured 31.7% / 30pp vs the committed
522
+ 68.92% / 28-28 - outside the correction budget, reverted clean.
523
+
524
+ ROOT CAUSE DECODED (the load-bearing finding): the OLD model
525
+ under-charges every counting flowable's space_before - ink is
526
+ drawn ABOVE the cursor, inside the previous flowable's consumed
527
+ space_after zone. The reference's calibrated constants ride that
528
+ under-charging; a geometrically correct model shifts every b>0
529
+ charge. Page-top behavior also differs from paper analysis
530
+ (heading ink at landings implies the old fresh-page path consumes
531
+ mt INSIDE the page - re-derive from HeadingFlowable's emit before
532
+ the next attempt, and note TableFlowable still needs the
533
+ convention added). Unification = dedicated re-tuning session, not
534
+ a release-day change. Full convention map now on Flowable's
535
+ contract doc.
536
+
515
537
  ## Measurement
516
538
 
517
539
  `bundle exec rake parity:check` — 64.07% (2026-08-17).
@@ -1,11 +1,13 @@
1
1
  # TODO.complete — Path to 100% mn2pdf parity
2
2
 
3
- ## Current baseline (2026-08-09)
3
+ ## Current baseline (2026-09-01)
4
4
 
5
- `bundle exec rake parity:check` reports **62.7%** overall similarity
6
- on the OIML r060/1 fixture, **28 pages vs 28 reference** (all pages PARTIAL+).
5
+ `bundle exec rake parity:check` reports **68.92%** overall similarity
6
+ on the OIML r060/1 fixture, **28 pages vs 28 reference**.
7
7
 
8
- 376 specs pass, 0 failures, 0 rubocop offenses across 174 files.
8
+ 452 specs pass, 0 failures, 0 rubocop offenses across 214 files.
9
+ TODO 96 is the live ledger (region deficits, keep-rule negative
10
+ results, the C2 margin decode).
9
11
 
10
12
  ## Status snapshot
11
13
 
@@ -16,6 +16,20 @@
16
16
  #
17
17
  # A flowable's height() and emit() must agree on whether margins
18
18
  # are included, or fit checks and drawing diverge.
19
+ #
20
+ # Convention map: TextFlowable (and HeadingFlowable, its
21
+ # subclass) count margins. ListFlowable + its subclasses (lists,
22
+ # notes), ImageFlowable, and TableFlowable do not — spacing
23
+ # around them travels as explicit Spacers.
24
+ #
25
+ # UNIFICATION DECODED (2026-08-31 attempt, reverted): the old
26
+ # model UNDER-CHARGES every counting flowable's space_before —
27
+ # its ink is drawn ABOVE the cursor, inside the previous
28
+ # flowable's already-consumed space_after zone. The reference's
29
+ # calibrated constants ride that under-charging. A correct CSS
30
+ # model (inset = max(pa,b) - pa + b, margins inside every
31
+ # flowable) measures 31.7% / 30pp: every b>0 charge shifts
32
+ # geometry. Unify only with a full re-tuning session.
19
33
  module Arrolio
20
34
  class Flowable
21
35
  attr_reader :style
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Arrolio
4
- VERSION = '0.1.4'
4
+ VERSION = '0.1.6'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arrolio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.