Skip to content

feat(layout/render): I-paged inline fragment tree — per-page slice + continuation rebase (slice 4 / I-paged)#282

Merged
send merged 3 commits into
mainfrom
worktree-slice4-i-paged
Jun 6, 2026
Merged

feat(layout/render): I-paged inline fragment tree — per-page slice + continuation rebase (slice 4 / I-paged)#282
send merged 3 commits into
mainfrom
worktree-slice4-i-paged

Conversation

@send

@send send commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Slice 4 / I-paged — inline fragment tree, first installment

The render↔layout inline-pipeline convergence's last structural gate was frag_constraint.is_some() routing paged/multicol inline to the legacy single-linear-pass path. This is the I-paged installment of slice 4: the inline portion of a Z-ready fragment tree, scoped to paged fragmentation (multicol = I-multicol, a separate slice; bidi/justify/text-transform remain independent slices; legacy deletion is terminal).

Plan-memo: render-layout-inline-convergence-slice4-fragtree-plan (/elidex-plan-review GREEN, 2-round). Master: render-layout-inline-convergence-plan §6 slice 4.

What changed

  • InlineFlow{ fragments: Vec<InlineFragment> } (InlineFragment { generation, lines }) — the inline node of the project's fragment tree. A 1-entity→N-fragment relation fits an ECS component, unlike the N:M entity↔layer relation that forces the layer tree into a standalone structure (design §15.4.1). Non-fragmented runs keep a single generation-0 fragment.
  • Paged-scoped persist gate (F3)fragmentation_type (Page/Column) threaded into InlineFragConstraint at both construction sites; the gate drops frag_constraint.is_none() for Page runs only. Multicol (Column) stays gated to legacy (its accumulate + column shift + balanced-fill probe-gating are I-multicol).
  • Single-source slice + continuation rebase (F2) — new LinePacker::slice_and_rebase_fragment: every block coordinate the packer records (flow lines, entity rects → LayoutBox/InlineClientRects, abspos static positions, positioned-atomic placements) is a snapshot of the same current_block_offset, so the slice to [skip_lines, effective_line_count) and the rebase to the fragmentainer block-start are applied once, before the content_origin fold — no cross-consumer desync.
  • Render consume — the consume gate + emit_inline_flow iterate fragments filtered by page generation (shared fragment_matches_page predicate keeps them in sync, D4).

Why

Paged multi-line inline was broken on both the (gated-off) persisted path and the box path (continuation geometry was never rebased — the founding gate test said so). This makes a page-spanning paragraph render correctly per fragment: continuation fragments rebased to the page content top, the tail dropped after an orphans/widows break.

Tests

6 new (5 layout + 1 render): paged-persists / multicol-still-gated / continuation-rebase / tail-drop-after-break / clientRects==flow-lines single-source / render-generation-filter. All changed-crate tests + full mise run ci (3-OS check + clippy + nextest + doc-tests + deny) green.

Gate

Full 6-stage pre-push: cargo fmtmise run ci (green) → /code-review (high; 0 real bugs) → /simplify (single-pass union + shared predicate) → /review/elidex-review (5-axis: 0 CRIT, fixed 1 IMP §15.4.1 citation + 1 IMP test-comment; 1 MIN inline/mod.rs 1103-line growth deferred consistent with prior slices). Cap-neutral (convergence/correctness refactor, no new #11-* slot).

🤖 Generated with Claude Code

send and others added 2 commits June 5, 2026 19:45
…continuation rebase (slice 4 / I-paged)

Generalize `InlineFlow` from a single generation-stamped line set to
`{ fragments: Vec<InlineFragment> }` (`InlineFragment { generation, lines }`)
— the inline node of the project's fragment tree (docs §15.5: a 1-entity →
N-fragment relation fits a component). Drop the `frag_constraint.is_none()`
term from the persist gate for **paged** runs only (`fragmentation_type ==
Page`, threaded into `InlineFragConstraint` at both construction sites);
multicol (`Column`) stays gated to legacy until I-multicol.

New `LinePacker::slice_and_rebase_fragment` is the single source (F2) of the
per-page slice + continuation rebase: every block coordinate the packer
records (flow lines, entity rects → LayoutBox/InlineClientRects, abspos static
positions, positioned-atomic placements) is a snapshot of the same
`current_block_offset`, so the slice to `[skip_lines, effective_line_count)`
and the rebase to the fragmentainer block-start are applied once, before the
`content_origin` fold. Render's consume gate + `emit_inline_flow` iterate
fragments filtered by the page generation (shared `fragment_matches_page`).

Fixes the founding gap: paged multi-line inline now renders per fragment
(continuation fragments rebased, tail dropped after a break) instead of
routing to the legacy single-linear-pass path. Cap-neutral.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n test

elidex-review Axis 4: the N:M entity↔layer "standalone structure" principle is
§15.4.1 "Layer Tree as Independent Structure", not §15.5 (= "Display List") —
correct both InlineFlow/InlineFragment docstrings. Axis 3: tie the inverted
gate test's justification to this slice's slice_and_rebase_fragment (the in-PR
root fix for the old gate's "not yet sliced per fragment" reason). Plus the
/simplify consolidations: single-pass entity-bounds union + shared
fragment_matches_page predicate (consume gate ⇄ emit filter parity).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 5, 2026 10:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the slice 4 / I-paged portion of the render↔layout inline convergence by introducing an inline fragment-tree representation (InlineFlowfragments: Vec<InlineFragment>) and enabling paged fragmentation to persist/consume per-page inline geometry via a single-source slice + continuation rebase pass.

Changes:

  • Introduces InlineFragment { generation, lines } and updates InlineFlow to carry per-fragment line sets (common case remains a single fragment via InlineFlow::single).
  • Adds LinePacker::slice_and_rebase_fragment(skip_lines, effective_line_count) and wires it into inline layout for paged fragmentation only (multicol/Column remains gated).
  • Updates render consumption to filter persisted fragments by page generation (shared fragment_matches_page predicate) and updates/extends tests accordingly.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
crates/layout/elidex-layout-block/src/inline/pack.rs Adds single-pass geometry slicing + continuation rebase for paged fragments.
crates/layout/elidex-layout-block/src/inline/mod.rs Threads fragmentation type into the gate and invokes slice+rebase for paged runs before consumers.
crates/core/elidex-ecs/src/components.rs Changes InlineFlow to hold Vec<InlineFragment> and adds InlineFlow::single helper.
crates/core/elidex-render/src/builder/inline.rs Consumes persisted inline flows per-page by filtering fragments by generation.
crates/core/elidex-render/src/builder/tests/inline_flow.rs Updates existing tests to build InlineFlow::single and adds generation-filter consume test.
crates/layout/elidex-layout-block/src/inline/tests/inline_flow.rs Updates tests for fragment-based flow and adds paged I-paged behavior tests (persist gate, rebase, tail drop, clientRects SSoT).
crates/layout/elidex-layout-block/src/inline/tests/relpos_subflow.rs Updates flow inspection to read from fragments[0].lines.
crates/layout/elidex-layout-block/src/block/children/shift.rs Shifts inline flow geometry across all fragments during subtree shifts.
crates/layout/elidex-layout-block/src/block/children/helpers.rs Threads fragmentation_type into InlineFragConstraint construction.
crates/layout/elidex-layout-block/src/block/mod.rs Threads fragmentation_type into inline fragmentation constraint for block layout.
crates/layout/elidex-layout-block/src/block/tests/margin_collapse.rs Updates test fixture construction to use InlineFlow::single and fragments[0].
crates/layout/elidex-layout-block/src/block/tests/fragmentation_advanced.rs Updates constraint construction to include fragmentation_type.
crates/core/elidex-ecs/src/lib.rs Re-exports InlineFragment.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@send

send commented Jun 5, 2026

Copy link
Copy Markdown
Owner Author

@codex[agent]

@send

send commented Jun 5, 2026

Copy link
Copy Markdown
Owner Author

@codex[agent] review

@send

send commented Jun 5, 2026

Copy link
Copy Markdown
Owner Author

@codex[agent] review deep

CSS Fragmentation L3 §4.3 is "Forced Breaks"; orphans/widows is css-break-3
§3.3 "Breaks Between Lines: orphans, widows" (#widows-orphans). Webref-verified
(`dfn css-break-3 orphans` → §3.3; `heading css-break-3 4.3` → Forced Breaks).
Repo-wide sibling sweep confirms these are the only orphans/widows mis-cites;
all other §4.3 references cite other specs (CSS Text/Lists/Selectors/Writing
Modes, HTML/DOM/XHR/Streams) and are correct. Comment/doc only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@send send merged commit dfe0e8f into main Jun 6, 2026
6 checks passed
send added a commit that referenced this pull request Jun 6, 2026
Comment/doc-only sweep correcting CSS Fragmentation Level 3 (css-break-3)
section citations in the block-layout fragmentation code. Surfaced during
the PR #282 citation sweep but unrelated to orphans/widows, so split out
here. No behavior or test-logic change. Every § re-verified with
.claude/tools/webref against css-break-3.

Verified spec structure (css-break-3):
  §3.1   break-before / break-after
  §3.1.1 Child→Parent Break Propagation
  §3.2   break-inside
  §3.3   orphans, widows           (← NOT break-inside / classification)
  §3.4   page-break-* aliases      (← NOT best-break selection)
  §4.1   Possible Break Points     (Class A/B/C, monolithic)
  §4.5   Optimizing Unforced Breaks (best break selection, avoid penalty)
  §5.2   Adjoining Margins at Breaks
  §5.4   box-decoration-break

Fixes (by drift cluster):
- break-inside §3.3 → §3.2  (elidex-plugin)
- box-decoration-break §4/§4.2 → §5.4  (elidex-plugin, doc plan)
- break propagation §3.2 → §3.1.1  (lib.rs, children/mod.rs, doc plan)
- break-point classification §3.3 → §4.1  (fragmentation.rs, float
  placement in stack.rs, doc plan)
- best-break selection / avoid penalty §3.4 → §4.5  (fragmentation.rs,
  stack.rs, doc plan)
- margins-not-collapsed-at-break §3.1 → §5.2  (stack.rs ×2, block/mod.rs)
- section-header ranges in fragmentation.rs: §3.3-§3.4 → §3.1-§3.2
  (avoid checks) and → §4.1, §4.5 (candidate selection)

Left as-is (verified correct / defensible): break-before/after §3.1,
forced-break detection §3.1, monolithic §4 (defined in §4.1), and the
orphans/widows §4.3 cites (handled separately, out of this cluster).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@send send deleted the worktree-slice4-i-paged branch June 6, 2026 00:27
send added a commit that referenced this pull request Jun 6, 2026
…on (#285)

Comment/doc-only sweep correcting CSS Fragmentation Level 3 (css-break-3)
section citations in the block-layout fragmentation code. No behavior or
test-logic change; every § re-verified with .claude/tools/webref.

- break-inside              §3.3 → §3.2
- break propagation         §3.2 → §3.1.1
- break-point classification §3.3 → §4.1
- best-break / avoid penalty §3.4 → §4.5
- margins-at-break          §3.1 → §5.2
- box-decoration-break      §4 / §4.2 → §5.4
- break-before/after        §3 → §3.1   (doc)
- fragmentainer context     §3 → §2     (doc)

Surfaced during the #282 citation sweep but unrelated to orphans/widows.
Copilot review found additional same-cluster instances (resolved in-PR).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants